diff options
Diffstat (limited to 'contrib/gcc')
55 files changed, 53234 insertions, 52783 deletions
diff --git a/contrib/gcc/FREEBSD-Xlist b/contrib/gcc/FREEBSD-Xlist new file mode 100644 index 0000000..96080bc --- /dev/null +++ b/contrib/gcc/FREEBSD-Xlist @@ -0,0 +1,93 @@ +# $FreeBSD$ +*.brik +*FAQ +*contrib +*etc +*faq.* +*/include +*/install* +*getopt* +*libchill +*libf2c +*libiberty +*libio +*libobjc +*libstdc++ +*lt* +*missing +*mkinstalldirs +*move-if-change +*symlink-tree +*texinfo +*ylwrap +*gcc/.cvsignore +*gcc/ABOUT*NLS +*gcc/*ChangeLog.* +*gcc/README.ACORN +*gcc/README.ALTOS +*gcc/README.APOLLO +*gcc/README.C4X +*gcc/README.FRESCO +*gcc/README.NS32K +*gcc/README.RS6000 +*gcc/README.X11 +*gcc/README.gnat +*gcc/*.bat +*gcc/*.com +*gcc/*.info* +*gcc/bi-parser.[ch] +*gcc/c-gperf.h +*gcc/c-parse.[chy] +*gcc/cexp.c +*gcc/cpp.aux +*gcc/cpp.cps +*gcc/cpp.fns +*gcc/gcc.aux +*gcc/gcc.cps +*gcc/gcc.hlp +*gcc/texinfo.tex +*gcc/.gdbinit +*gcc/install1.texi +*gcc/intl +*gcc/ch +*gcc/cp/hash.h +*gcc/cp/parse.[ch] +*gcc/config/1750a +*gcc/config/a29k +*gcc/config/arc +*gcc/config/arm +*gcc/config/c4x +*gcc/config/clipper +*gcc/config/convex +*gcc/config/dsp16xx +*gcc/config/elxsi +*gcc/config/fx80 +*gcc/config/gmicro +*gcc/config/h8300 +*gcc/config/i370 +*gcc/config/i860 +*gcc/config/i960 +*gcc/config/m32r +*gcc/config/m68k +*gcc/config/m88k +*gcc/config/mn10200 +*gcc/config/mn10300 +*gcc/config/msdos +*gcc/config/ns32k +*gcc/config/pa +*gcc/config/pdp11 +*gcc/config/pyr +*gcc/config/romp +*gcc/config/rs6000 +*gcc/config/sh +*gcc/config/spur +*gcc/config/tahoe +*gcc/config/v850 +*gcc/config/vax +*gcc/config/we32k +*gcc/config/winnt +*gcc/fixinc +*gcc/java +*gcc/objc/objc-parse.[cy] +*gcc/po +*gcc/testsuite diff --git a/contrib/gcc/FREEBSD-deletelist b/contrib/gcc/FREEBSD-deletelist new file mode 100644 index 0000000..f5bc817 --- /dev/null +++ b/contrib/gcc/FREEBSD-deletelist @@ -0,0 +1,87 @@ +$FreeBSD$ +CVS +.cvsignore +ABOUT*NLS +ChangeLog.lib +FSFChangeLog.* +README.ACORN +README.ALTOS +README.APOLLO +README.AVR +README.C4X +README.FRESCO +README.NS32K +README.RS6000 +README.X11 +README.gnat +*.bat +*.com +*.info* +bi-parser.[ch] +c-gperf.h +c-parse.[chy] +cexp.c +cpp.aux +cpp.cps +cpp.fns +gcc.aux +gcc.cps +gcc.hlp +getopt.[ch] +texinfo.tex +.gdbinit +install1.texi +intl +ch +cp/cfns.[chy] +cp/hash.h +cp/parse.[ch] +config/1750a +config/a29k +config/arc +config/arm +config/avr +config/c4x +config/clipper +config/convex +config/d30v +config/dsp16xx +config/elxsi +config/fr30 +config/fx80 +config/gmicro +config/h8300 +config/i370 +config/i860 +config/i960 +config/m32r +config/m68k +config/m88k +config/mcore +config/mips +config/mn10200 +config/mn10300 +config/msdos +config/ns32k +config/pa +config/pdp11 +config/pj +config/pyr +config/romp +config/rs6000 +config/sh +config/spur +config/tahoe +config/v850 +config/vax +config/we32k +config/winnt +fixinc +gccbug* +java +mkinstalldirs +objc/objc-parse.[cy] +gthr-win32* +po +testsuite +tradcif.c diff --git a/contrib/gcc/FREEBSD-libiberty b/contrib/gcc/FREEBSD-libiberty new file mode 100644 index 0000000..1b8c249 --- /dev/null +++ b/contrib/gcc/FREEBSD-libiberty @@ -0,0 +1,37 @@ +#! /bin/sh + +# $FreeBSD$ + +for F in \ + choose-temp.c \ + cp-demangle.c \ + cplus-dem.c \ + dyn-string.c \ + getopt.c \ + getopt1.c \ + getpwd.c \ + hashtab.c \ + lbasename.c \ + md5.c \ + obstack.c \ + partition.c \ + pexecute.c \ + splay-tree.c +do + cp -ip ../libiberty/$F . +done + +for F in \ + ansidecl.h \ + demangle.h \ + dyn-string.h \ + getopt.h \ + hashtab.h \ + libiberty.h \ + obstack.h \ + partition.h \ + splay-tree.h \ + symcat.h +do + cp -ip ../include/$F . +done diff --git a/contrib/gcc/FREEBSD-upgrade b/contrib/gcc/FREEBSD-upgrade new file mode 100644 index 0000000..922f8eb --- /dev/null +++ b/contrib/gcc/FREEBSD-upgrade @@ -0,0 +1,13 @@ +$FreeBSD$ + +tar -xvjf gcc-3.0.2.tar.bz2 -X FREEBSD-Xlist + +cd gcc-3.0.2/gcc +sh FREEBSD-libiberty + +cvs import src/contrib/gcc FSF gcc_3_0_2 + +If you decide to bring in more of the files, import them -- don't +use ``cvs add''. And please remember to adjust the contents of +"FREEBSD-Xlist" so that it reflects what is really imported from +the vendor. diff --git a/contrib/gcc/Makefile.in b/contrib/gcc/Makefile.in index 8c02cce..30815af 100644 --- a/contrib/gcc/Makefile.in +++ b/contrib/gcc/Makefile.in @@ -1,9 +1,8 @@ # Makefile for GNU Compiler Collection # Run 'configure' to generate Makefile from Makefile.in -# Copyright (C) 1987, 1988, 1990, 1991, 1992, 1993, 1994, 1995, 1996, -# 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 -# Free Software Foundation, Inc. +# Copyright (C) 1987, 1988, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +# 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. #This file is part of GCC. @@ -19,8 +18,8 @@ #You should have received a copy of the GNU General Public License #along with GCC; see the file COPYING. If not, write to -#the Free Software Foundation, 51 Franklin Street, Fifth Floor, -#Boston MA 02110-1301, USA. +#the Free Software Foundation, 59 Temple Place - Suite 330, +#Boston MA 02111-1307, USA. # The targets for external use include: # all, doc, proto, install, install-cross, install-cross-rest, @@ -72,30 +71,18 @@ program_transform_name := @program_transform_name@ # Directory where sources are, from where we are. srcdir = @srcdir@ -gcc_docdir = @srcdir@/doc +docdir = @srcdir@/doc # Directory where sources are, absolute. abs_srcdir = @abs_srcdir@ abs_docdir = @abs_srcdir@/doc -# Top build directory for this package, relative to here. -top_builddir = . +# Top build directory, relative to here. +top_builddir = .. # objdir is set by configure. # It's normally the absolute path to the current directory. objdir = @objdir@ -host_subdir=@host_subdir@ -build_subdir=@build_subdir@ -build_libsubdir=@build_libsubdir@ - -ifeq ($(host_subdir),.) -build_objdir := ../$(build_subdir) -build_libobjdir := ../$(build_libsubdir) -else -build_objdir := ../../$(build_subdir) -build_libobjdir := ../../$(build_libsubdir) -endif - # -------- # Defined vpaths # -------- @@ -103,12 +90,12 @@ endif # Directory where sources are, from where we are. VPATH = @srcdir@ -# We define a vpath for the sources of the .texi files here because they +# We define a vpath for the sources of the .texi files here because they # are split between multiple directories and we would rather use one implicit # pattern rule for everything. # This vpath could be extended within the Make-lang fragments. -vpath %.texi $(gcc_docdir):$(gcc_docdir)/include +vpath %.texi $(docdir):$(docdir)/include # ---- # Default values for variables overridden in Makefile fragments. @@ -130,10 +117,10 @@ T_ADAFLAGS = # See below for how to change them for certain systems. # List of language subdirectories. -SUBDIRS =@subdirs@ build +SUBDIRS =@subdirs@ # Selection of languages to be made. -CONFIG_LANGUAGES = @all_selected_languages@ +CONFIG_LANGUAGES = @all_languages@ LANGUAGES = c gcov$(exeext) gcov-dump$(exeext) $(CONFIG_LANGUAGES) # Selection of languages to be made during stage1 build. @@ -145,17 +132,14 @@ BOOT_LANGUAGES = c @all_boot_languages@ # or BOOT_CFLAGS # STAGE1_CFLAGS is set by configure on some targets or passed from toplevel # and sets the CFLAGS passed to stage1 of a bootstrap compilation. -# STAGE1_CHECKING enables checking for the stage1 compiler # BOOT_CFLAGS is the value of CFLAGS to pass to the stage2, stage3 and stage4 # bootstrap compilations. # XCFLAGS is used for most compilations but not when using the GCC just built. # TCFLAGS is used for compilations with the GCC just built. XCFLAGS = TCFLAGS = -CFLAGS = @CFLAGS@ -LDFLAGS = @LDFLAGS@ +CFLAGS = -g STAGE1_CFLAGS = -g @stage1_cflags@ -STAGE1_CHECKING_CFLAGS = -DENABLE_CHECKING -DENABLE_ASSERT_CHECKING BOOT_CFLAGS = -g -O2 # Flags to determine code coverage. When coverage is disabled, this will @@ -175,16 +159,10 @@ coverageexts = .{gcda,gcno} # STRICT_WARN and STRICT2_WARN are the additional warning flags to # apply to the back end and the C front end, which may be compiled # with other compilers. This is partially controlled by configure in -# stage1, as not all versions of gcc understand -Wno-long-long or -# -Wno-variadic-macros. -# CXX_COMPAT_WARN are C++ source compatibility warnings. +# stage1, as not all versions of gcc understand -Wno-long-long. LOOSE_WARN = -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes STRICT_WARN = @strict1_warn@ -WERROR_FLAGS = @WERROR@ -STRICT2_WARN = -pedantic -Wno-long-long -Wno-variadic-macros \ - -Wno-overlength-strings -Wold-style-definition -Wmissing-format-attribute \ - $(WERROR_FLAGS) -CXX_COMPAT_WARN = @cxx_compat_warn@ +STRICT2_WARN = -pedantic -Wno-long-long -Wold-style-definition @WERROR@ # This is set by --enable-checking. The idea is to catch forgotten # "extern" tags in header files. @@ -199,23 +177,19 @@ VALGRIND_DRIVER_DEFINES = @valgrind_path_defines@ # This is how we control whether or not the additional warnings are applied. .-warn = $(STRICT_WARN) -build-warn = $(STRICT_WARN) GCC_WARN_CFLAGS = $(LOOSE_WARN) $($(@D)-warn) $(NOCOMMON_FLAG) $($@-warn) -# These files are to have specific diagnostics suppressed, or are not to -# be subject to -Werror: +# These files are to have -Werror bypassed in stage2: +# These are very hard to completely clean due to target complexities. +gcc.o-warn = -Wno-error +insn-conditions.o-warn = -Wno-error # Bison-1.75 output often yields (harmless) -Wtraditional warnings -build/gengtype-yacc.o-warn = -Wno-error +gengtype-yacc.o-warn = -Wno-error +c-parse.o-warn = -Wno-error # flex output may yield harmless "no previous prototype" warnings -build/gengtype-lex.o-warn = -Wno-error +gengtype-lex.o-warn = -Wno-error # SYSCALLS.c misses prototypes SYSCALLS.c.X-warn = -Wno-strict-prototypes -Wno-error -# These files need -Wno-error because the gimplifier triggers hard to fix -# warnings when converting to GIMPLE form. The warnings are triggered because -# moving the condition into the loop prevents the loop optimizer from -# recognizing that the loop will always be executed at least once. We need -# a new loop optimizer. -reload1.o-warn = -Wno-error # All warnings have to be shut off in stage1 if the compiler used then # isn't gcc; configure determines that. WARN_CFLAGS will be either @@ -237,11 +211,9 @@ BISON = @BISON@ BISONFLAGS = FLEX = @FLEX@ FLEXFLAGS = -AR = @AR@ +AR = ar AR_FLAGS = rc -NM = @NM@ RANLIB = @RANLIB@ -RANLIB_FLAGS = @ranlib_flags@ # ------------------------------------------- # Programs which operate on the build machine @@ -268,8 +240,6 @@ INSTALL_SCRIPT = @INSTALL@ MAKEINFO = @MAKEINFO@ MAKEINFOFLAGS = --no-split TEXI2DVI = texi2dvi -TEXI2PDF = texi2pdf -TEXI2HTML = $(MAKEINFO) --html TEXI2POD = perl $(srcdir)/../contrib/texi2pod.pl POD2MAN = pod2man --center="GNU" --release="gcc-$(version)" # Some versions of `touch' (such as the version on Solaris 2.8) @@ -281,9 +251,6 @@ STAMP = echo timestamp > @SET_MAKE@ REMAKEFLAGS=LANGUAGES="$(LANGUAGES)" BOOT_CFLAGS="$(BOOT_CFLAGS)" -# Locate mkinstalldirs. -mkinstalldirs=$(SHELL) $(srcdir)/../mkinstalldirs - # -------- # UNSORTED # -------- @@ -298,18 +265,6 @@ OUTPUT_OPTION = @OUTPUT_OPTION@ ZLIB = @zlibdir@ -lz ZLIBINC = @zlibinc@ -# How to find GMP -GMPLIBS = @GMPLIBS@ -GMPINC = @GMPINC@ - -CPPLIB = ../libcpp/libcpp.a -CPPINC = -I$(srcdir)/../libcpp/include - -# Where to find decNumber -DECNUM = $(srcdir)/../libdecnumber -DECNUMINC = -I$(DECNUM) -I../libdecnumber -LIBDECNUMBER = ../libdecnumber/libdecnumber.a - # Substitution type for target's getgroups 2nd arg. TARGET_GETGROUPS_T = @TARGET_GETGROUPS_T@ @@ -319,17 +274,15 @@ INSTALL_HEADERS_DIR = @build_install_headers_dir@ # Header files that are made available under the same name # to programs compiled with GCC. -USER_H = $(srcdir)/ginclude/decfloat.h \ - $(srcdir)/ginclude/float.h \ +USER_H = $(srcdir)/ginclude/float.h \ $(srcdir)/ginclude/iso646.h \ $(srcdir)/ginclude/stdarg.h \ $(srcdir)/ginclude/stdbool.h \ $(srcdir)/ginclude/stddef.h \ $(srcdir)/ginclude/varargs.h \ + $(srcdir)/unwind.h \ $(EXTRA_HEADERS) -UNWIND_H = $(srcdir)/unwind-generic.h - # The GCC to use for compiling libgcc.a and crt*.o. # Usually the one we just built. # Don't use this as a dependency--use $(GCC_PASSES) or $(GCC_PARTS). @@ -338,28 +291,26 @@ GCC_FOR_TARGET = $(STAGE_CC_WRAPPER) ./xgcc -B./ -B$(build_tooldir)/bin/ -isyste # This is used instead of ALL_CFLAGS when compiling with GCC_FOR_TARGET. # It omits XCFLAGS, and specifies -B./. # It also specifies -isystem ./include to find, e.g., stddef.h. -GCC_CFLAGS=$(CFLAGS_FOR_TARGET) $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(LOOSE_WARN) -Wold-style-definition $($@-warn) -isystem ./include $(TCFLAGS) +GCC_CFLAGS=$(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(LOOSE_WARN) -Wold-style-definition $($@-warn) -isystem ./include $(TCFLAGS) # --------------------------------------------------- # Programs which produce files for the target machine # --------------------------------------------------- -AR_FOR_TARGET := $(shell \ +AR_FOR_TARGET = ` \ if [ -f $(objdir)/../binutils/ar ] ; then \ echo $(objdir)/../binutils/ar ; \ else \ if [ "$(host)" = "$(target)" ] ; then \ - echo $(AR); \ + echo ar; \ else \ t='$(program_transform_name)'; echo ar | sed -e $$t ; \ fi; \ - fi) + fi` AR_FLAGS_FOR_TARGET = AR_CREATE_FOR_TARGET = $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) rc AR_EXTRACT_FOR_TARGET = $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) x -LIPO_FOR_TARGET = lipo -ORIGINAL_AS_FOR_TARGET = @ORIGINAL_AS_FOR_TARGET@ -RANLIB_FOR_TARGET := $(shell \ +RANLIB_FOR_TARGET = ` \ if [ -f $(objdir)/../binutils/ranlib ] ; then \ echo $(objdir)/../binutils/ranlib ; \ else \ @@ -368,20 +319,19 @@ RANLIB_FOR_TARGET := $(shell \ else \ t='$(program_transform_name)'; echo ranlib | sed -e $$t ; \ fi; \ - fi) -ORIGINAL_LD_FOR_TARGET = @ORIGINAL_LD_FOR_TARGET@ -ORIGINAL_NM_FOR_TARGET = @ORIGINAL_NM_FOR_TARGET@ -NM_FOR_TARGET = ./nm -STRIP_FOR_TARGET := $(shell \ - if [ -f $(objdir)/../binutils/strip ] ; then \ - echo $(objdir)/../binutils/strip ; \ + fi` +NM_FOR_TARGET = ` \ + if [ -f ./nm ] ; then \ + echo ./nm ; \ + elif [ -f $(objdir)/../binutils/nm-new ] ; then \ + echo $(objdir)/../binutils/nm-new ; \ else \ if [ "$(host)" = "$(target)" ] ; then \ - echo strip; \ + echo nm; \ else \ - t='$(program_transform_name)'; echo strip | sed -e $$t ; \ + t='$(program_transform_name)'; echo nm | sed -e $$t ; \ fi; \ - fi) + fi` # -------- # UNSORTED @@ -393,7 +343,6 @@ OBSTACK_H = $(srcdir)/../include/obstack.h SPLAY_TREE_H= $(srcdir)/../include/splay-tree.h FIBHEAP_H = $(srcdir)/../include/fibheap.h PARTITION_H = $(srcdir)/../include/partition.h -MD5_H = $(srcdir)/../include/md5.h # Default native SYSTEM_HEADER_DIR, to be overridden by targets. NATIVE_SYSTEM_HEADER_DIR = /usr/include @@ -401,12 +350,7 @@ NATIVE_SYSTEM_HEADER_DIR = /usr/include CROSS_SYSTEM_HEADER_DIR = @CROSS_SYSTEM_HEADER_DIR@ # autoconf sets SYSTEM_HEADER_DIR to one of the above. -# Purge it of unneccessary internal relative paths -# to directories that might not exist yet. -# The sed idiom for this is to repeat the search-and-replace until it doesn't match, using :a ... ta. -# Use single quotes here to avoid nested double- and backquotes, this -# macro is also used in a double-quoted context. -SYSTEM_HEADER_DIR = `echo @SYSTEM_HEADER_DIR@ | sed -e :a -e 's,[^/]*/\.\.\/,,' -e ta` +SYSTEM_HEADER_DIR = @SYSTEM_HEADER_DIR@ # Control whether to run fixproto and fixincludes. STMP_FIXPROTO = @STMP_FIXPROTO@ @@ -447,8 +391,12 @@ GCC_THREAD_FILE=@thread_file@ OBJC_BOEHM_GC=@objc_boehm_gc@ GTHREAD_FLAGS=@gthread_flags@ extra_modes_file=@extra_modes_file@ -extra_opt_files=@extra_opt_files@ host_hook_obj=@out_host_hook_obj@ +# Be prepared for gcc2 merges. +gcc_version=@gcc_version@ +gcc_version_trigger=@gcc_version_trigger@ +version=$(gcc_version) +mainversion=`grep version_string $(srcdir)/version.c | sed -e 's/.*\"\([0-9]*\.[0-9]*\).*/\1/'` # ------------------------ # Installation directories @@ -515,13 +463,6 @@ man7dir = $(mandir)/man7 # Dir for temp files. tmpdir = /tmp -datarootdir = @datarootdir@ -docdir = @docdir@ -# Directory in which to build HTML -build_htmldir = $(objdir)/HTML/gcc-$(version) -# Directory in which to put HTML -htmldir = @htmldir@ - # Whether we were configured with NLS. USE_NLS = @USE_NLS@ @@ -544,20 +485,10 @@ GGC_LIB= LIBGCC = libgcc.a INSTALL_LIBGCC = install-libgcc -# "true" if the target C library headers are unavailable; "false" -# otherwise. -inhibit_libc = @inhibit_libc@ -ifeq ($(inhibit_libc),true) -INHIBIT_LIBC_CFLAGS = -Dinhibit_libc -endif - # Options to use when compiling libgcc2.a. # LIBGCC2_DEBUG_CFLAGS = -g -LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(TARGET_LIBGCC2_CFLAGS) \ - $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) \ - -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED \ - $(INHIBIT_LIBC_CFLAGS) +LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(TARGET_LIBGCC2_CFLAGS) $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED @inhibit_libc@ # Additional options to use when compiling libgcc2.a. # Some targets override this to -isystem include @@ -569,15 +500,14 @@ TARGET_LIBGCC2_CFLAGS = # Options to use when compiling crtbegin/end. CRTSTUFF_CFLAGS = -O2 $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \ -finhibit-size-directive -fno-inline-functions -fno-exceptions \ - -fno-zero-initialized-in-bss -fno-toplevel-reorder \ - $(INHIBIT_LIBC_CFLAGS) + -fno-zero-initialized-in-bss -fno-unit-at-a-time # Additional sources to handle exceptions; overridden by targets as needed. LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \ $(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c $(srcdir)/unwind-c.c LIB2ADDEHSTATIC = $(LIB2ADDEH) LIB2ADDEHSHARED = $(LIB2ADDEH) -LIB2ADDEHDEP = $(UNWIND_H) unwind-pe.h unwind.inc unwind-dw2-fde.h unwind-dw2.h +LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h # Don't build libunwind by default. LIBUNWIND = @@ -611,10 +541,9 @@ EXTRA_GCC_OBJS =@extra_gcc_objs@ # List of additional header files to install. EXTRA_HEADERS =@extra_headers_list@ -# The configure script will set this to collect2$(exeext), except on a -# (non-Unix) host which can not build collect2, for which it will be -# set to empty. -COLLECT2 = @collect2@ +# It is convenient for configure to add the assignment at the beginning, +# so don't override it here. +USE_COLLECT2 = collect2$(exeext) # List of extra C and assembler files to add to static and shared libgcc2. # Assembler files should have names ending in `.asm'. @@ -624,11 +553,9 @@ LIB2FUNCS_EXTRA = # Assembler files should have names ending in `.asm'. LIB2FUNCS_STATIC_EXTRA = -# List of functions not to build from libgcc2.c. -LIB2FUNCS_EXCLUDE = - -# Target sfp-machine.h file. -SFP_MACHINE = +# List of extra C and assembler files to add to shared libgcc2. +# Assembler files should have names ending in `.asm'. +LIB2FUNCS_SHARED_EXTRA = # Program to convert libraries. LIBCONVERT = @@ -659,11 +586,20 @@ GCC_PASSES=xgcc$(exeext) cc1$(exeext) specs $(EXTRA_PASSES) # List of things which should already be built whenever we try to use xgcc # to link anything. -GCC_PARTS=$(GCC_PASSES) $(LIBGCC) $(EXTRA_PROGRAMS) $(COLLECT2) $(EXTRA_PARTS) +GCC_PARTS=$(GCC_PASSES) $(LIBGCC) $(EXTRA_PROGRAMS) $(USE_COLLECT2) $(EXTRA_PARTS) # Directory to link to, when using the target `maketest'. DIR = ../gcc +# Flags to use when cross-building GCC. +# Prefix to apply to names of object files when using them +# to run on the machine we are compiling on. +BUILD_PREFIX = @BUILD_PREFIX@ +# Prefix to apply to names of object files when compiling them +# to run on the machine we are compiling on. +# The default for this variable is chosen to keep these rules +# out of the way of the other rules for compiling the same source files. +BUILD_PREFIX_1 = @BUILD_PREFIX_1@ # Native compiler for the build machine and its switches. CC_FOR_BUILD = @CC_FOR_BUILD@ BUILD_CFLAGS= @BUILD_CFLAGS@ -DGENERATOR_FILE @@ -725,97 +661,40 @@ CONFIG_H = config.h $(host_xm_file_list) TCONFIG_H = tconfig.h $(xm_file_list) TM_P_H = tm_p.h $(tm_p_file_list) GTM_H = tm.h $(tm_file_list) -TM_H = $(GTM_H) insn-constants.h insn-flags.h options.h - -# Variables for version information. -BASEVER := $(srcdir)/BASE-VER # 4.x.y -DEVPHASE := $(srcdir)/DEV-PHASE # experimental, prerelease, "" -DATESTAMP := $(srcdir)/DATESTAMP # YYYYMMDD or empty - -BASEVER_c := $(shell cat $(BASEVER)) -DEVPHASE_c := $(shell cat $(DEVPHASE)) -DATESTAMP_c := $(shell cat $(DATESTAMP)) - -version := $(BASEVER_c) - -# For use in version.c - double quoted strings, with appropriate -# surrounding punctuation and spaces, and with the datestamp and -# development phase collapsed to the empty string in release mode -# (i.e. if DEVPHASE_c is empty). The space immediately after the -# comma in the $(if ...) constructs is significant - do not remove it. -BASEVER_s := "\"$(BASEVER_c)\"" -DEVPHASE_s := "\"$(if $(DEVPHASE_c), ($(DEVPHASE_c)))\"" -DATESTAMP_s := "\"$(if $(DEVPHASE_c), $(DATESTAMP_c))\"" - -# Shorthand variables for dependency lists. -TARGET_H = $(TM_H) target.h insn-modes.h -MACHMODE_H = machmode.h mode-classes.def insn-modes.h -HOOKS_H = hooks.h $(MACHMODE_H) -HOSTHOOKS_DEF_H = hosthooks-def.h $(HOOKS_H) +TM_H = $(GTM_H) insn-constants.h insn-flags.h + +TARGET_H = $(TM_H) target.h +HOOKS_H = hooks.h LANGHOOKS_DEF_H = langhooks-def.h $(HOOKS_H) TARGET_DEF_H = target-def.h $(HOOKS_H) -RTL_BASE_H = rtl.h rtl.def $(MACHMODE_H) reg-notes.def insn-notes.def \ - input.h $(REAL_H) statistics.h vec.h -RTL_H = $(RTL_BASE_H) genrtl.h +MACHMODE_H = machmode.h mode-classes.def insn-modes.h +RTL_BASE_H = rtl.h rtl.def $(MACHMODE_H) +RTL_H = $(RTL_BASE_H) genrtl.h input.h PARAMS_H = params.h params.def -BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def -TREE_H = tree.h tree.def $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \ - input.h statistics.h vec.h treestruct.def $(HASHTAB_H) +TREE_H = tree.h tree.def $(MACHMODE_H) tree-check.h version.h builtins.def \ + input.h BASIC_BLOCK_H = basic-block.h bitmap.h sbitmap.h varray.h $(PARTITION_H) \ - hard-reg-set.h cfghooks.h $(OBSTACK_H) -GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h -COVERAGE_H = coverage.h $(GCOV_IO_H) + hard-reg-set.h cfghooks.h +COVERAGE_H = coverage.h gcov-io.h gcov-iov.h DEMANGLE_H = $(srcdir)/../include/demangle.h RECOG_H = recog.h -ALIAS_H = alias.h -EMIT_RTL_H = emit-rtl.h -FLAGS_H = flags.h options.h -FUNCTION_H = function.h $(TREE_H) $(HASHTAB_H) -EXPR_H = expr.h insn-config.h $(FUNCTION_H) $(RTL_H) $(FLAGS_H) $(TREE_H) $(MACHMODE_H) $(EMIT_RTL_H) +EXPR_H = expr.h OPTABS_H = optabs.h insn-codes.h -REGS_H = regs.h varray.h $(MACHMODE_H) $(OBSTACK_H) $(BASIC_BLOCK_H) $(FUNCTION_H) -RESOURCE_H = resource.h hard-reg-set.h -SCHED_INT_H = sched-int.h $(INSN_ATTR_H) $(BASIC_BLOCK_H) $(RTL_H) -INTEGRATE_H = integrate.h $(VARRAY_H) -CFGLAYOUT_H = cfglayout.h $(BASIC_BLOCK_H) -CFGLOOP_H = cfgloop.h $(BASIC_BLOCK_H) $(RTL_H) -IPA_UTILS_H = ipa-utils.h $(TREE_H) $(CGRAPH_H) -IPA_REFERENCE_H = ipa-reference.h bitmap.h $(TREE_H) -IPA_TYPE_ESCAPE_H = ipa-type-escape.h $(TREE_H) -CGRAPH_H = cgraph.h $(TREE_H) -DF_H = df.h bitmap.h $(BASIC_BLOCK_H) alloc-pool.h -DDG_H = ddg.h sbitmap.h $(DF_H) +REGS_H = regs.h varray.h $(MACHMODE_H) +INTEGRATE_H = integrate.h varray.h +LOOP_H = loop.h varray.h bitmap.h GCC_H = gcc.h version.h GGC_H = ggc.h gtype-desc.h TIMEVAR_H = timevar.h timevar.def INSN_ATTR_H = insn-attr.h $(srcdir)/insn-addr.h $(srcdir)/varray.h -C_COMMON_H = c-common.h $(SPLAY_TREE_H) $(CPPLIB_H) $(GGC_H) -C_PRAGMA_H = c-pragma.h $(CPPLIB_H) -C_TREE_H = c-tree.h $(C_COMMON_H) toplev.h $(DIAGNOSTIC_H) -SYSTEM_H = system.h hwint.h double-int.h $(srcdir)/../include/libiberty.h +C_COMMON_H = c-common.h $(SPLAY_TREE_H) $(CPPLIB_H) +C_TREE_H = c-tree.h $(C_COMMON_H) +SYSTEM_H = system.h hwint.h $(srcdir)/../include/libiberty.h PREDICT_H = predict.h predict.def -CPPLIB_H = $(srcdir)/../libcpp/include/line-map.h \ - $(srcdir)/../libcpp/include/cpplib.h -DECNUM_H = $(DECNUM)/decContext.h $(DECNUM)/decDPD.h $(DECNUM)/decNumber.h \ - $(DECNUM)/decimal32.h $(DECNUM)/decimal64.h $(DECNUM)/decimal128.h -MKDEPS_H = $(srcdir)/../libcpp/include/mkdeps.h -SYMTAB_H = $(srcdir)/../libcpp/include/symtab.h -CPP_ID_DATA_H = $(CPPLIB_H) $(srcdir)/../libcpp/include/cpp-id-data.h -TREE_DUMP_H = tree-dump.h $(SPLAY_TREE_H) -TREE_GIMPLE_H = tree-gimple.h tree-iterator.h -TREE_FLOW_H = tree-flow.h tree-flow-inline.h tree-ssa-operands.h \ - bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h $(TREE_GIMPLE_H) \ - $(HASHTAB_H) $(CGRAPH_H) $(IPA_REFERENCE_H) -TREE_SSA_LIVE_H = tree-ssa-live.h $(PARTITION_H) vecprim.h +CPPLIB_H = cpplib.h line-map.h PRETTY_PRINT_H = pretty-print.h input.h $(OBSTACK_H) -DIAGNOSTIC_H = diagnostic.h diagnostic.def $(PRETTY_PRINT_H) options.h -C_PRETTY_PRINT_H = c-pretty-print.h $(PRETTY_PRINT_H) $(C_COMMON_H) $(TREE_H) -SCEV_H = tree-scalar-evolution.h $(GGC_H) tree-chrec.h $(PARAMS_H) -LAMBDA_H = lambda.h $(TREE_H) vec.h $(GGC_H) -TREE_DATA_REF_H = tree-data-ref.h $(LAMBDA_H) -VARRAY_H = varray.h $(MACHMODE_H) $(SYSTEM_H) coretypes.h $(TM_H) -TREE_INLINE_H = tree-inline.h $(VARRAY_H) $(SPLAY_TREE_H) -REAL_H = real.h $(MACHMODE_H) +DIAGNOSTIC_H = diagnostic.h diagnostic.def $(PRETTY_PRINT_H) +C_PRETTY_PRINT_H = $(PRETTY_PRINT_H) $(C_COMMON_H) $(TREE_H) # # Now figure out from those variables how to compile and link. @@ -830,17 +709,16 @@ INTERNAL_CFLAGS = -DIN_GCC @CROSS@ ALL_CFLAGS = $(X_CFLAGS) $(T_CFLAGS) \ $(CFLAGS) $(INTERNAL_CFLAGS) $(COVERAGE_FLAGS) $(WARN_CFLAGS) $(XCFLAGS) @DEFS@ -# Likewise. Put INCLUDES at the beginning: this way, if some autoconf macro -# puts -I options in CPPFLAGS, our include files in the srcdir will always -# win against random include files in /usr/include. -ALL_CPPFLAGS = $(INCLUDES) $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS) +# Likewise. +ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS) -# Build and host support libraries. +# Build and host support libraries. FORBUILD is either +# .. or ../$(build_alias) depending on whether host != build. LIBIBERTY = ../libiberty/libiberty.a -BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/libiberty.a +BUILD_LIBIBERTY = @FORBUILD@/libiberty/libiberty.a # Dependencies on the intl and portability libraries. -LIBDEPS= $(CPPLIB) $(LIBIBERTY) $(LIBINTL_DEP) $(LIBICONV_DEP) $(LIBDECNUMBER) +LIBDEPS= $(LIBIBERTY) $(LIBINTL_DEP) $(LIBICONV_DEP) # Likewise, for use in the tools that must run on this machine # even if we are cross-building GCC. @@ -848,7 +726,7 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY) # How to link with both our special library facilities # and the system's installed libraries. -LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) $(LIBDECNUMBER) +LIBS = @LIBS@ $(LIBIBERTY) $(LIBINTL) $(LIBICONV) # Any system libraries needed just for GNAT. SYSLIBS = @GNAT_LIBEXC@ @@ -860,9 +738,14 @@ LDEXP_LIB = @LDEXP_LIB@ # even if we are cross-building GCC. BUILD_LIBS = $(BUILD_LIBIBERTY) -BUILD_RTL = build/rtl.o build/read-rtl.o build/ggc-none.o build/vec.o \ - build/min-insn-modes.o build/gensupport.o build/print-rtl.o -BUILD_ERRORS = build/errors.o +BUILD_RTL = $(BUILD_PREFIX)rtl.o read-rtl.o $(BUILD_PREFIX)bitmap.o \ + $(BUILD_PREFIX)ggc-none.o min-insn-modes.o +BUILD_SUPPORT = gensupport.o insn-conditions.o +BUILD_EARLY_SUPPORT = gensupport.o dummy-conditions.o + +BUILD_PRINT = print-rtl1.o +BUILD_ERRORS = $(BUILD_PREFIX)errors.o +BUILD_VARRAY = $(BUILD_PREFIX)varray.o # Specify the directories to be searched for header files. # Both . and srcdir are used, in that order, @@ -872,11 +755,10 @@ BUILD_ERRORS = build/errors.o # currently being compiled, in both source trees, to be examined as well. # libintl.h will be found in ../intl if we are using the included libintl. INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \ - -I$(srcdir)/../include @INCINTL@ \ - $(CPPINC) $(GMPINC) $(DECNUMINC) + -I$(srcdir)/../include @INCINTL@ .c.o: - $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) # # Support for additional languages (other than C). @@ -897,16 +779,16 @@ export AR_CREATE_FOR_TARGET export AR_FLAGS_FOR_TARGET export AR_EXTRACT_FOR_TARGET export AWK +export BUILD_PREFIX +export BUILD_PREFIX_1 export DESTDIR export GCC_FOR_TARGET export INCLUDES export INSTALL_DATA export LIB1ASMSRC export LIBGCC2_CFLAGS -export LIPO_FOR_TARGET export MACHMODE_H export NM_FOR_TARGET -export STRIP_FOR_TARGET export RANLIB_FOR_TARGET export libsubdir export slibdir @@ -951,115 +833,84 @@ SUBDIR_FLAGS_TO_PASS = $(ORDINARY_FLAGS_TO_PASS) \ # # Lists of files for various purposes. -# All option source files -ALL_OPT_FILES=$(lang_opt_files) $(extra_opt_files) - # Target specific, C specific object file C_TARGET_OBJS=@c_target_objs@ # Target specific, C++ specific object file CXX_TARGET_OBJS=@cxx_target_objs@ -# Object files for gcc driver. -GCC_OBJS = gcc.o opts-common.o gcc-options.o - # Language-specific object files for C and Objective C. C_AND_OBJC_OBJS = attribs.o c-errors.o c-lex.o c-pragma.o c-decl.o c-typeck.o \ c-convert.o c-aux-info.o c-common.o c-opts.o c-format.o c-semantics.o \ c-incpath.o cppdefault.o c-ppoutput.o c-cppbuiltin.o prefix.o \ - c-objc-common.o c-dump.o c-pch.o c-parser.o $(C_TARGET_OBJS) \ - c-gimplify.o tree-mudflap.o c-pretty-print.o c-omp.o + c-objc-common.o c-dump.o c-pch.o libcpp.a $(C_TARGET_OBJS) # Language-specific object files for C. -C_OBJS = c-lang.o stub-objc.o $(C_AND_OBJC_OBJS) +C_OBJS = c-parse.o c-lang.o c-pretty-print.o stub-objc.o $(C_AND_OBJC_OBJS) # Language-independent object files. + OBJS-common = \ - double-int.o tree-chrec.o tree-scalar-evolution.o tree-data-ref.o \ - tree-cfg.o tree-dfa.o tree-eh.o tree-ssa.o tree-optimize.o tree-gimple.o \ - gimplify.o tree-pretty-print.o tree-into-ssa.o \ - tree-outof-ssa.o tree-ssa-ccp.o tree-vn.o tree-ssa-uncprop.o \ - tree-ssa-dce.o tree-ssa-copy.o tree-nrv.o tree-ssa-copyrename.o \ - tree-ssa-pre.o tree-ssa-live.o tree-ssa-operands.o tree-ssa-alias.o \ - tree-ssa-phiopt.o tree-ssa-forwprop.o tree-nested.o tree-ssa-dse.o \ - tree-ssa-dom.o domwalk.o tree-tailcall.o gimple-low.o tree-iterator.o \ - omp-low.o tree-phinodes.o tree-ssanames.o tree-sra.o tree-complex.o \ - tree-vect-generic.o tree-ssa-loop.o tree-ssa-loop-niter.o \ - tree-ssa-loop-manip.o tree-ssa-threadupdate.o tree-ssa-threadedge.o \ - tree-vectorizer.o tree-vect-analyze.o tree-vect-transform.o \ - tree-vect-patterns.o tree-ssa-loop-prefetch.o \ - tree-ssa-loop-ivcanon.o tree-ssa-propagate.o tree-ssa-address.o \ - tree-ssa-math-opts.o \ - tree-ssa-loop-ivopts.o tree-if-conv.o tree-ssa-loop-unswitch.o \ alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \ cfg.o cfganal.o cfgbuild.o cfgcleanup.o cfglayout.o cfgloop.o \ cfgloopanal.o cfgloopmanip.o loop-init.o loop-unswitch.o loop-unroll.o \ cfgrtl.o combine.o conflict.o convert.o coverage.o cse.o cselib.o \ - dbxout.o ddg.o tree-ssa-loop-ch.o loop-invariant.o tree-ssa-loop-im.o \ - debug.o df-core.o df-problems.o df-scan.o dfp.o diagnostic.o dojump.o \ - dominance.o loop-doloop.o \ - dwarf2asm.o dwarf2out.o emit-rtl.o except.o explow.o loop-iv.o \ + dbxout.o debug.o df.o diagnostic.o dojump.o doloop.o dominance.o \ + dwarf2asm.o dwarf2out.o emit-rtl.o except.o explow.o \ expmed.o expr.o final.o flow.o fold-const.o function.o gcse.o \ genrtl.o ggc-common.o global.o graph.o gtype-desc.o \ haifa-sched.o hooks.o ifcvt.o insn-attrtab.o insn-emit.o insn-modes.o \ insn-extract.o insn-opinit.o insn-output.o insn-peep.o insn-recog.o \ integrate.o intl.o jump.o langhooks.o lcm.o lists.o local-alloc.o \ - mode-switching.o modulo-sched.o optabs.o options.o opts.o opts-common.o \ - params.o postreload.o postreload-gcse.o predict.o \ - insn-preds.o insn-automata.o pointer-set.o \ - print-rtl.o print-tree.o profile.o value-prof.o var-tracking.o \ + loop.o optabs.o options.o opts.o params.o postreload.o predict.o \ + print-rtl.o print-tree.o value-prof.o \ + profile.o ra.o ra-build.o ra-colorize.o ra-debug.o ra-rewrite.o \ real.o recog.o reg-stack.o regclass.o regmove.o regrename.o \ reload.o reload1.o reorg.o resource.o rtl.o rtlanal.o rtl-error.o \ sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o \ - see.o simplify-rtx.o sreal.o stmt.o stor-layout.o stringpool.o \ - struct-equiv.o targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o \ - varasm.o varray.o vec.o version.o vmsdbgout.o xcoffout.o alloc-pool.o \ - et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o \ - tree-profile.o rtlhooks.o cfgexpand.o lambda-mat.o \ - lambda-trans.o lambda-code.o tree-loop-linear.o tree-ssa-sink.o \ - tree-vrp.o tree-stdarg.o tree-cfgcleanup.o tree-ssa-reassoc.o \ - tree-ssa-structalias.o tree-object-size.o \ - rtl-factoring.o - + sibcall.o simplify-rtx.o sreal.o stmt.o stor-layout.o stringpool.o \ + targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o unroll.o \ + varasm.o varray.o version.o vmsdbgout.o xcoffout.o alloc-pool.o \ + et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o OBJS-md = $(out_object_file) -OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o \ - cgraph.o cgraphunit.o tree-nomudflap.o ipa.o ipa-inline.o \ - ipa-utils.o ipa-reference.o ipa-pure-const.o ipa-type-escape.o \ - ipa-prop.o ipa-cp.o +OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o tree-inline.o \ + tree-optimize.o cgraph.o cgraphunit.o OBJS = $(OBJS-common) $(out_object_file) $(OBJS-archive) OBJS-onestep = libbackend.o $(OBJS-archive) -BACKEND = main.o @TREEBROWSER@ libbackend.a $(CPPLIB) $(LIBDECNUMBER) +BACKEND = main.o libbackend.a -# Files to be copied after each stage in building. -STAGECOPYSTUFF = insn-flags.h insn-config.h insn-codes.h \ +# Files to be copied away after each stage in building. +STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \ insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \ - insn-attr.h insn-attrtab.c insn-opinit.c insn-preds.c insn-constants.h \ - tm-preds.h tm-constrs.h \ - tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \ - genrtl.c genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-gen.h - -# Files to be moved away after each stage in building. -STAGEMOVESTUFF = *$(objext) s-* \ - xgcc$(exeext) cpp$(exeext) cc1$(exeext) cc1*-dummy$(exeext) $(EXTRA_PASSES) \ + insn-attr.h insn-attrtab.c insn-opinit.c insn-constants.h tm-preds.h \ + tree-check.h insn-conditions.c min-insn-modes.c insn-modes.c insn-modes.h \ + s-flags s-config s-codes s-mlib s-genrtl s-modes s-gtype gtyp-gen.h \ + s-output s-recog s-emit s-extract s-peep s-check s-conditions \ + s-attr s-attrtab s-opinit s-preds s-constants s-crt0 \ + genemit$(build_exeext) genoutput$(build_exeext) genrecog$(build_exeext) \ + genextract$(build_exeext) genflags$(build_exeext) gencodes$(build_exeext) \ + genconfig$(build_exeext) genpeep$(build_exeext) genattrtab$(build_exeext) \ + genattr$(build_exeext) genopinit$(build_exeext) gengenrtl$(build_exeext) \ + gencheck$(build_exeext) genpreds$(build_exeext) genconstants$(build_exeext) \ + gengtype$(build_exeext) genconditions$(build_exeext) genmodes$(build_exeext) \ + genrtl.c genrtl.h gt-*.h gtype-*.h gtype-desc.c \ + xgcc$(exeext) cpp$(exeext) cc1$(exeext) $(EXTRA_PASSES) \ $(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) \ protoize$(exeext) unprotoize$(exeext) \ - $(SPECS) collect2$(exeext) \ + $(SPECS) collect2$(exeext) $(USE_COLLECT2) \ gcov-iov$(build_exeext) gcov$(exeext) gcov-dump$(exeext) \ - *.[0-9][0-9].* *.[si] *-checksum.c libbackend.a libgcc.mk \ + *.[0-9][0-9].* *.[si] libcpp.a libbackend.a libgcc.mk \ $(LANG_STAGESTUFF) # Defined in libgcc2.c, included only in the static library. LIB2FUNCS_ST = _eprintf __gcc_bcmp # Defined in libgcov.c, included only in gcov library -LIBGCOV = _gcov _gcov_merge_add _gcov_merge_single _gcov_merge_delta \ - _gcov_fork _gcov_execl _gcov_execlp _gcov_execle \ - _gcov_execv _gcov_execvp _gcov_execve \ - _gcov_interval_profiler _gcov_pow2_profiler _gcov_one_value_profiler +LIBGCOV = _gcov _gcov_merge_add _gcov_merge_single _gcov_merge_delta FPBIT_FUNCS = _pack_sf _unpack_sf _addsub_sf _mul_sf _div_sf \ _fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \ @@ -1076,29 +927,6 @@ TPBIT_FUNCS = _pack_tf _unpack_tf _addsub_tf _mul_tf _div_tf \ _lt_tf _le_tf _unord_tf _si_to_tf _tf_to_si _negate_tf _make_tf \ _tf_to_df _tf_to_sf _thenan_tf _tf_to_usi _usi_to_tf -D32PBIT_FUNCS = _addsub_sd _div_sd _mul_sd _plus_sd _minus_sd \ - _eq_sd _ne_sd _lt_sd _gt_sd _le_sd _ge_sd \ - _sd_to_si _sd_to_di _sd_to_usi _sd_to_udi \ - _si_to_sd _di_to_sd _usi_to_sd _udi_to_sd \ - _sd_to_sf _sd_to_df _sd_to_xf _sf_to_sd _df_to_sd _xf_to_sd \ - _sd_to_dd _sd_to_td _unord_sd _conv_sd - -D64PBIT_FUNCS = _addsub_dd _div_dd _mul_dd _plus_dd _minus_dd \ - _eq_dd _ne_dd _lt_dd _gt_dd _le_dd _ge_dd \ - _dd_to_si _dd_to_di _dd_to_usi _dd_to_udi \ - _si_to_dd _di_to_dd _usi_to_dd _udi_to_dd \ - _dd_to_sf _dd_to_df _dd_to_xf \ - _sf_to_dd _df_to_dd _xf_to_dd \ - _dd_to_sd _dd_to_td _unord_dd _conv_dd - -D128PBIT_FUNCS = _addsub_td _div_td _mul_td _plus_td _minus_td \ - _eq_td _ne_td _lt_td _gt_td _le_td _ge_td \ - _td_to_si _td_to_di _td_to_usi _td_to_udi \ - _si_to_td _di_to_td _usi_to_td _udi_to_td \ - _td_to_sf _td_to_df _td_to_xf \ - _sf_to_td _df_to_td _xf_to_td \ - _td_to_sd _td_to_dd _unord_td _conv_td - # These might cause a divide overflow trap and so are compiled with # unwinder info. LIB2_DIVMOD_FUNCS = _divdi3 _moddi3 _udivdi3 _umoddi3 _udiv_w_sdiv _udivmoddi4 @@ -1109,7 +937,7 @@ LIB2_DIVMOD_FUNCS = _divdi3 _moddi3 _udivdi3 _umoddi3 _udiv_w_sdiv _udivmoddi4 # The following targets define the interface between us and the languages. # # all.cross, start.encap, rest.encap, -# install-common, install-info, install-man, +# install-normal, install-common, install-info, install-man, # uninstall, # mostlyclean, clean, distclean, maintainer-clean, # stage1, stage2, stage3, stage4 @@ -1122,6 +950,9 @@ LIB2_DIVMOD_FUNCS = _divdi3 _moddi3 _udivdi3 _umoddi3 _udiv_w_sdiv _udivmoddi4 # language hooks, generated by configure @language_hooks@ +# Set up library path if needed. +@set_gcc_lib_path@ + # per-language makefile fragments ifneq ($(LANG_MAKEFRAGS),) include $(LANG_MAKEFRAGS) @@ -1146,43 +977,7 @@ endif # Rebuilding this configuration # ----------------------------- -# On the use of stamps: -# Consider the example of tree-check.h. It is constructed with build/gencheck. -# A simple rule to build tree-check.h would be -# tree-check.h: build/gencheck$(build_exeext) -# $(RUN_GEN) build/gencheck$(build_exeext) > tree-check.h -# -# but tree-check.h doesn't change every time gencheck changes. It would the -# nice if targets that depend on tree-check.h wouldn't be rebuild -# unnecessarily when tree-check.h is unchanged. To make this, tree-check.h -# must not be overwritten with a identical copy. One solution is to use a -# temporary file -# tree-check.h: build/gencheck$(build_exeext) -# $(RUN_GEN) build/gencheck$(build_exeext) > tmp-check.h -# $(SHELL) $(srcdir)/../move-if-change tmp-check.h tree-check.h -# -# This solution has a different problem. Since the time stamp of tree-check.h -# is unchanged, make will try to update tree-check.h every time it runs. -# To prevent this, one can add a stamp -# tree-check.h: s-check -# s-check : build/gencheck$(build_exeext) -# $(RUN_GEN) build/gencheck$(build_exeext) > tmp-check.h -# $(SHELL) $(srcdir)/../move-if-change tmp-check.h tree-check.h -# $(STAMP) s-check -# -# The problem with this solution is that make thinks that tree-check.h is -# always unchanged. Make must be deceived into thinking that tree-check.h is -# rebuild by the "tree-check.h: s-check" rule. To do this, add a dummy command: -# tree-check.h: s-check; @true -# s-check : build/gencheck$(build_exeext) -# $(RUN_GEN) build/gencheck$(build_exeext) > tmp-check.h -# $(SHELL) $(srcdir)/../move-if-change tmp-check.h tree-check.h -# $(STAMP) s-check -# -# This is what is done in this makefile. Note that mkconfig.sh has a -# move-if-change built-in - -Makefile: config.status $(srcdir)/Makefile.in $(LANG_MAKEFRAGS) +Makefile: config.status $(srcdir)/Makefile.in $(srcdir)/version.c $(LANG_MAKEFRAGS) LANGUAGES="$(CONFIG_LANGUAGES)" \ CONFIG_HEADERS= \ CONFIG_SHELL="$(SHELL)" \ @@ -1206,7 +1001,7 @@ cs-bconfig.h: Makefile cs-tconfig.h: Makefile TARGET_CPU_DEFAULT="" \ - HEADERS="$(xm_include_list)" DEFINES="USED_FOR_TARGET $(xm_defines)" \ + HEADERS="$(xm_include_list)" DEFINES="$(xm_defines)" \ $(SHELL) $(srcdir)/mkconfig.sh tconfig.h cs-tm.h: Makefile @@ -1224,8 +1019,7 @@ cs-tm_p.h: Makefile # might be on a read-only file system. If configured for maintainer mode # then do allow autoconf to be run. -$(srcdir)/configure: @MAINT@ $(srcdir)/configure.ac $(srcdir)/aclocal.m4 \ - $(srcdir)/acinclude.m4 +$(srcdir)/configure: @MAINT@ $(srcdir)/configure.ac (cd $(srcdir) && autoconf) gccbug: $(srcdir)/gccbug.in @@ -1234,6 +1028,9 @@ gccbug: $(srcdir)/gccbug.in mklibgcc: $(srcdir)/mklibgcc.in CONFIG_FILES=mklibgcc CONFIG_HEADERS= ./config.status +mkheaders: $(srcdir)/mkheaders.in + CONFIG_FILES=mkheaders CONFIG_HEADERS= ./config.status + # cstamp-h.in controls rebuilding of config.in. # It is named cstamp-h.in and not stamp-h.in so the mostlyclean rule doesn't # delete it. A stamp file is needed as autoheader won't update the file if @@ -1260,7 +1057,7 @@ cstamp-h: config.in config.status # Really, really stupid make features, such as SUN's KEEP_STATE, may force # a target to build even if it is up-to-date. So we must verify that # config.status does not exist before failing. -config.status: $(srcdir)/configure $(srcdir)/config.gcc +config.status: $(srcdir)/configure $(srcdir)/config.gcc version.c @if [ ! -f config.status ] ; then \ echo You must configure gcc. Look at http://gcc.gnu.org/install/ for details.; \ false; \ @@ -1274,8 +1071,8 @@ config.status: $(srcdir)/configure $(srcdir)/config.gcc all.internal: start.encap rest.encap doc # This is what to compile if making a cross-compiler. -all.cross: native gcc-cross$(exeext) cpp$(exeext) specs \ - $(LIBGCC) $(EXTRA_PARTS) lang.all.cross doc @GENINSRC@ srcextra +all.cross: native gcc-cross cpp$(exeext) specs \ + $(LIBGCC) $(EXTRA_PARTS) lang.all.cross doc # This is what must be made before installing GCC and converting libraries. start.encap: native xgcc$(exeext) cpp$(exeext) specs \ xlimits.h lang.start.encap @GENINSRC@ srcextra @@ -1284,13 +1081,14 @@ rest.encap: $(STMP_FIXPROTO) $(LIBGCC) $(EXTRA_PARTS) lang.rest.encap # This is what is made with the host's compiler # whether making a cross compiler or not. native: config.status auto-host.h build-@POSUB@ $(LANGUAGES) \ - $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(COLLECT2) + $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(USE_COLLECT2) # Define the names for selecting languages in LANGUAGES. -c: cc1$(exeext) +C c: cc1$(exeext) +PROTO: proto # Tell GNU make these are phony targets. -.PHONY: c proto +.PHONY: C c PROTO proto # On the target machine, finish building a cross compiler. # This does the things that can't be done on the host machine. @@ -1300,81 +1098,27 @@ rest.cross: $(LIBGCC) specs # This is used only if the user explicitly asks for it. compilations: $(BACKEND) -# This archive is strictly for the host. +# Like libcpp.a, this archive is strictly for the host. libbackend.a: $(OBJS@onestep@) -rm -rf libbackend.a $(AR) $(AR_FLAGS) libbackend.a $(OBJS@onestep@) - -$(RANLIB) $(RANLIB_FLAGS) libbackend.a + -$(RANLIB) libbackend.a # We call this executable `xgcc' rather than `gcc' # to avoid confusion if the current directory is in the path # and CC is `gcc'. It is renamed to `gcc' when it is installed. -xgcc$(exeext): $(GCC_OBJS) gccspec.o version.o intl.o prefix.o \ +xgcc$(exeext): gcc.o gccspec.o version.o intl.o prefix.o \ version.o $(LIBDEPS) $(EXTRA_GCC_OBJS) - $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(GCC_OBJS) gccspec.o \ - intl.o prefix.o version.o $(EXTRA_GCC_OBJS) $(LIBS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ gcc.o gccspec.o intl.o \ + prefix.o version.o $(EXTRA_GCC_OBJS) $(LIBS) # cpp is to cpp0 as gcc is to cc1. # The only difference from xgcc is that it's linked with cppspec.o # instead of gccspec.o. -cpp$(exeext): $(GCC_OBJS) cppspec.o version.o intl.o prefix.o \ +cpp$(exeext): gcc.o cppspec.o version.o intl.o prefix.o \ version.o $(LIBDEPS) $(EXTRA_GCC_OBJS) - $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(GCC_OBJS) cppspec.o \ - intl.o prefix.o version.o $(EXTRA_GCC_OBJS) $(LIBS) - -# Create links to binutils, especially for in-tree builds, to make -B. -# use them. We need hard links so that directories can be shuffled -# during toplevel bootstrap. -# Go through an additional indirection, because the file we create -# can be either `sometool' (if it is a script) or `sometool$(exeext)' -# (if it is a hard link). -stamp-as: $(ORIGINAL_AS_FOR_TARGET) - @echo creating as; \ - case "$(ORIGINAL_AS_FOR_TARGET)" in \ - ./as) ;; \ - ../*) \ - rm -f as$(exeext); \ - echo $(LN) $< as$(exeext); \ - $(LN) $< as$(exeext) || cp $< as$(exeext) ;; \ - *) \ - rm -f as; \ - echo '#!$(SHELL)' > as; \ - echo 'exec $(ORIGINAL_AS_FOR_TARGET) "$$@"' >> as ; \ - chmod +x as ;; \ - esac - echo timestamp > $@ - -stamp-collect-ld: $(ORIGINAL_LD_FOR_TARGET) - @echo creating collect-ld; \ - case "$(ORIGINAL_LD_FOR_TARGET)" in \ - ./collect-ld) ;; \ - ../*) \ - rm -f collect-ld$(exeext); \ - echo $(LN) $< collect-ld$(exeext); \ - $(LN) $< collect-ld$(exeext) || cp $< collect-ld$(exeext) ;; \ - *) \ - rm -f collect-ld$(exeext); \ - echo '#!$(SHELL)' > collect-ld; \ - echo 'exec $(ORIGINAL_LD_FOR_TARGET) "$$@"' >> collect-ld ; \ - chmod +x collect-ld ;; \ - esac - echo timestamp > $@ - -stamp-nm: $(ORIGINAL_NM_FOR_TARGET) - @echo creating nm; \ - case "$(ORIGINAL_NM_FOR_TARGET)" in \ - ./nm) ;; \ - ../*) \ - rm -f nm$(exeext); \ - echo $(LN) $< nm$(exeext); \ - $(LN) $< nm$(exeext) || cp $< nm$(exeext) ;; \ - *) \ - rm -f nm$(exeext); \ - echo '#!$(SHELL)' > nm; \ - echo 'exec $(ORIGINAL_NM_FOR_TARGET) "$$@"' >> nm ; \ - chmod +x nm ;; \ - esac - echo timestamp > $@ + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ gcc.o cppspec.o intl.o \ + prefix.o version.o $(EXTRA_GCC_OBJS) $(LIBS) # Dump a specs file to make -B./ read these specs over installed ones. $(SPECS): xgcc$(exeext) @@ -1384,23 +1128,12 @@ $(SPECS): xgcc$(exeext) # We do want to create an executable named `xgcc', so we can use it to # compile libgcc2.a. # Also create gcc-cross, so that install-common will install properly. -gcc-cross$(exeext): xgcc$(exeext) +gcc-cross: xgcc$(exeext) cp xgcc$(exeext) gcc-cross$(exeext) -dummy-checksum.o : dummy-checksum.c - -cc1-dummy$(exeext): $(C_OBJS) dummy-checksum.o $(BACKEND) $(LIBDEPS) - $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(C_OBJS) dummy-checksum.o \ - $(BACKEND) $(LIBS) - -cc1-checksum.c : cc1-dummy$(exeext) build/genchecksum$(build_exeext) - build/genchecksum$(build_exeext) cc1-dummy$(exeext) > $@ - -cc1-checksum.o : cc1-checksum.c - -cc1$(exeext): $(C_OBJS) cc1-checksum.o $(BACKEND) $(LIBDEPS) - $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(C_OBJS) cc1-checksum.o \ - $(BACKEND) $(LIBS) +cc1$(exeext): $(C_OBJS) $(BACKEND) $(LIBDEPS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1$(exeext) \ + $(C_OBJS) $(BACKEND) $(LIBS) # Build the version of limits.h that we will install. xlimits.h: glimits.h limitx.h limity.h @@ -1415,21 +1148,21 @@ xlimits.h: glimits.h limitx.h limity.h LIB2ADD = $(LIB2FUNCS_EXTRA) LIB2ADD_ST = $(LIB2FUNCS_STATIC_EXTRA) +LIB2ADD_SH = $(LIB2FUNCS_SHARED_EXTRA) -libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) $(LIB2ADD_ST) specs \ - xgcc$(exeext) stamp-as stamp-collect-ld stamp-nm +libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) $(LIB2ADD_ST) $(LIB2ADD_SH) \ + xgcc$(exeext) specs objext='$(objext)' \ LIB1ASMFUNCS='$(LIB1ASMFUNCS)' \ LIB2FUNCS_ST='$(LIB2FUNCS_ST)' \ - LIB2FUNCS_EXCLUDE='$(LIB2FUNCS_EXCLUDE)' \ LIBGCOV='$(LIBGCOV)' \ LIB2ADD='$(LIB2ADD)' \ LIB2ADD_ST='$(LIB2ADD_ST)' \ + LIB2ADD_SH='$(LIB2ADD_SH)' \ LIB2ADDEH='$(LIB2ADDEH)' \ LIB2ADDEHSTATIC='$(LIB2ADDEHSTATIC)' \ LIB2ADDEHSHARED='$(LIB2ADDEHSHARED)' \ LIB2ADDEHDEP='$(LIB2ADDEHDEP)' \ - LIB2_SIDITI_CONV_FUNCS='$(LIB2_SIDITI_CONV_FUNCS)' \ LIBUNWIND='$(LIBUNWIND)' \ LIBUNWINDDEP='$(LIBUNWINDDEP)' \ SHLIBUNWIND_LINK='$(SHLIBUNWIND_LINK)' \ @@ -1441,14 +1174,6 @@ libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) $(LIB2ADD_ST) specs \ DPBIT_FUNCS='$(DPBIT_FUNCS)' \ TPBIT='$(TPBIT)' \ TPBIT_FUNCS='$(TPBIT_FUNCS)' \ - DFP_ENABLE='$(DFP_ENABLE)' \ - DFP_CFLAGS='$(DFP_CFLAGS)' \ - D32PBIT='$(D32PBIT)' \ - D32PBIT_FUNCS='$(D32PBIT_FUNCS)' \ - D64PBIT='$(D64PBIT)' \ - D64PBIT_FUNCS='$(D64PBIT_FUNCS)' \ - D128PBIT='$(D128PBIT)' \ - D128PBIT_FUNCS='$(D128PBIT_FUNCS)' \ MULTILIBS=`$(GCC_FOR_TARGET) --print-multi-lib` \ EXTRA_MULTILIB_PARTS='$(EXTRA_MULTILIB_PARTS)' \ SHLIB_LINK='$(SHLIB_LINK)' \ @@ -1460,21 +1185,18 @@ libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) $(LIB2ADD_ST) specs \ SHLIB_MAPFILES='$(SHLIB_MAPFILES)' \ SHLIB_NM_FLAGS='$(SHLIB_NM_FLAGS)' \ MULTILIB_OSDIRNAMES='$(MULTILIB_OSDIRNAMES)' \ - ASM_HIDDEN_OP='$(ASM_HIDDEN_OP)' \ - GCC_FOR_TARGET='$(GCC_FOR_TARGET)' \ - mkinstalldirs='$(mkinstalldirs)' \ + mkinstalldirs='$(SHELL) $(srcdir)/mkinstalldirs' \ $(SHELL) mklibgcc > tmp-libgcc.mk mv tmp-libgcc.mk libgcc.mk # All the things that might cause us to want to recompile bits of libgcc. -LIBGCC_DEPS = $(GCC_PASSES) stmp-int-hdrs $(STMP_FIXPROTO) \ +LIBGCC_DEPS = $(GCC_PASSES) $(LANGUAGES) stmp-int-hdrs $(STMP_FIXPROTO) \ libgcc.mk $(srcdir)/libgcc2.c $(srcdir)/libgcov.c $(TCONFIG_H) \ - $(MACHMODE_H) longlong.h gbl-ctors.h config.status $(srcdir)/libgcc2.h \ + $(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs \ tsystem.h $(FPBIT) $(DPBIT) $(TPBIT) $(LIB2ADD) \ - config/dfp-bit.h config/dfp-bit.c \ - $(LIB2ADD_ST) $(LIB2ADDEH) $(LIB2ADDEHDEP) $(EXTRA_PARTS) \ - $(srcdir)/config/$(LIB1ASMSRC) \ - $(srcdir)/gcov-io.h $(srcdir)/gcov-io.c gcov-iov.h $(SFP_MACHINE) + $(LIB2ADD_ST) $(LIB2ADD_SH) $(LIB2ADDEH) $(LIB2ADDEHDEP) \ + $(EXTRA_PARTS) $(srcdir)/config/$(LIB1ASMSRC) \ + $(srcdir)/gcov-io.h $(srcdir)/gcov-io.c gcov-iov.h libgcov.a: libgcc.a; @true @@ -1507,7 +1229,7 @@ s-mlib: $(srcdir)/genmultilib Makefile $(SHELL) $(srcdir)/genmultilib '' '' '' '' '' '' '' no \ > tmp-mlib.h; \ fi - $(SHELL) $(srcdir)/../move-if-change tmp-mlib.h multilib.h + $(SHELL) $(srcdir)/move-if-change tmp-mlib.h multilib.h $(STAMP) s-mlib # Build multiple copies of libgcc.a, one for each target switch. @@ -1525,33 +1247,33 @@ stmp-multilib: $(LIBGCC_DEPS) $(T)crtbegin.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \ gbl-ctors.h stmp-int-hdrs tsystem.h coretypes.h $(TM_H) $(GCC_FOR_TARGET) $(CRTSTUFF_CFLAGS) $(CRTSTUFF_T_CFLAGS) \ - -c $(srcdir)/crtstuff.c -DCRT_BEGIN \ + @inhibit_libc@ -c $(srcdir)/crtstuff.c -DCRT_BEGIN \ -o $(T)crtbegin$(objext) $(T)crtend.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \ gbl-ctors.h stmp-int-hdrs tsystem.h coretypes.h $(TM_H) $(GCC_FOR_TARGET) $(CRTSTUFF_CFLAGS) $(CRTSTUFF_T_CFLAGS) \ - -c $(srcdir)/crtstuff.c -DCRT_END \ + @inhibit_libc@ -c $(srcdir)/crtstuff.c -DCRT_END \ -o $(T)crtend$(objext) # These are versions of crtbegin and crtend for shared libraries. $(T)crtbeginS.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \ gbl-ctors.h stmp-int-hdrs tsystem.h coretypes.h $(TM_H) $(GCC_FOR_TARGET) $(CRTSTUFF_CFLAGS) $(CRTSTUFF_T_CFLAGS_S) \ - -c $(srcdir)/crtstuff.c -DCRT_BEGIN -DCRTSTUFFS_O \ + @inhibit_libc@ -c $(srcdir)/crtstuff.c -DCRT_BEGIN -DCRTSTUFFS_O \ -o $(T)crtbeginS$(objext) $(T)crtendS.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \ gbl-ctors.h stmp-int-hdrs tsystem.h coretypes.h $(TM_H) $(GCC_FOR_TARGET) $(CRTSTUFF_CFLAGS) $(CRTSTUFF_T_CFLAGS_S) \ - -c $(srcdir)/crtstuff.c -DCRT_END -DCRTSTUFFS_O \ + @inhibit_libc@ -c $(srcdir)/crtstuff.c -DCRT_END -DCRTSTUFFS_O \ -o $(T)crtendS$(objext) # This is a version of crtbegin for -static links. $(T)crtbeginT.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \ gbl-ctors.h stmp-int-hdrs tsystem.h coretypes.h $(TM_H) $(GCC_FOR_TARGET) $(CRTSTUFF_CFLAGS) $(CRTSTUFF_T_CFLAGS) \ - -c $(srcdir)/crtstuff.c -DCRT_BEGIN -DCRTSTUFFT_O \ + @inhibit_libc@ -c $(srcdir)/crtstuff.c -DCRT_BEGIN -DCRTSTUFFT_O \ -o $(T)crtbeginT$(objext) # Compile the start modules crt0.o and mcrt0.o that are linked with @@ -1574,62 +1296,60 @@ s-crt0: $(CRT0_S) $(MCRT0_S) $(GCC_PASSES) $(CONFIG_H) # C language specific files. c-errors.o: c-errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) $(TM_P_H) -c-parser.o : c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(GGC_H) $(TIMEVAR_H) $(C_TREE_H) input.h $(FLAGS_H) toplev.h output.h \ - $(CPPLIB_H) gt-c-parser.h langhooks.h $(C_COMMON_H) $(C_PRAGMA_H) \ - vec.h $(TARGET_H) + $(C_TREE_H) flags.h $(DIAGNOSTIC_H) $(TM_P_H) +c-parse.o : c-parse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(GGC_H) intl.h $(C_TREE_H) input.h flags.h toplev.h output.h $(CPPLIB_H) \ + varray.h gt-c-parse.h srcextra: gcc.srcextra lang.srcextra -gcc.srcextra: gengtype-lex.c gengtype-yacc.c gengtype-yacc.h +gcc.srcextra: c-parse.y c-parse.c gengtype-lex.c gengtype-yacc.c gengtype-yacc.h -cp -p $^ $(srcdir) +c-parse.c: c-parse.y + -$(BISON) $(BISONFLAGS) -o $@ $< + +c-parse.y: c-parse.in + echo '/*WARNING: This file is automatically generated!*/' >tmp-c-parse.y + sed -e "/^@@ifobjc.*/,/^@@end_ifobjc.*/d" \ + -e "/^@@ifc.*/d" -e "/^@@end_ifc.*/d" $< >>tmp-c-parse.y + $(SHELL) $(srcdir)/move-if-change tmp-c-parse.y $@ + c-incpath.o: c-incpath.c c-incpath.h $(CONFIG_H) $(SYSTEM_H) $(CPPLIB_H) \ - intl.h prefix.h coretypes.h $(TM_H) cppdefault.h $(TARGET_H) \ - $(MACHMODE_H) + intl.h prefix.h coretypes.h $(TM_H) cppdefault.h c-decl.o : c-decl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(RTL_H) $(C_TREE_H) $(GGC_H) $(TARGET_H) $(FLAGS_H) $(FUNCTION_H) output.h \ - $(EXPR_H) debug.h toplev.h intl.h $(TM_P_H) $(TREE_INLINE_H) $(TIMEVAR_H) \ - opts.h $(C_PRAGMA_H) gt-c-decl.h $(CGRAPH_H) $(HASHTAB_H) libfuncs.h \ - except.h $(LANGHOOKS_DEF_H) $(TREE_DUMP_H) $(C_COMMON_H) $(CPPLIB_H) \ - $(DIAGNOSTIC_H) input.h langhooks.h $(TREE_GIMPLE_H) tree-mudflap.h \ - pointer-set.h -c-typeck.o : c-typeck.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(C_TREE_H) $(TARGET_H) $(FLAGS_H) intl.h output.h $(EXPR_H) \ - $(RTL_H) toplev.h $(TM_P_H) langhooks.h $(GGC_H) $(TREE_FLOW_H) \ - $(TREE_GIMPLE_H) tree-iterator.h + $(RTL_H) $(C_TREE_H) $(GGC_H) $(TARGET_H) flags.h function.h output.h \ + $(EXPR_H) debug.h toplev.h intl.h $(TM_P_H) tree-inline.h $(TIMEVAR_H) \ + opts.h c-pragma.h gt-c-decl.h cgraph.h $(HASHTAB_H) libfuncs.h except.h \ + $(LANGHOOKS_DEF_H) +c-typeck.o : c-typeck.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \ + $(TARGET_H) flags.h intl.h output.h $(EXPR_H) $(RTL_H) toplev.h $(TM_P_H) c-lang.o : c-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) $(DIAGNOSTIC_H) \ - $(GGC_H) langhooks.h $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-c.h \ - c-objc-common.h $(C_PRAGMA_H) c-common.def $(TREE_INLINE_H) + $(C_TREE_H) $(C_PRETTY_PRINT_H) $(DIAGNOSTIC_H) \ + $(GGC_H) langhooks.h $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-c.h stub-objc.o : stub-objc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ - $(C_COMMON_H) + $(GGC_H) $(C_COMMON_H) c-lex.o : c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(RTL_H) debug.h $(C_TREE_H) $(C_COMMON_H) $(REAL_H) $(SPLAY_TREE_H) \ - $(C_PRAGMA_H) input.h intl.h $(FLAGS_H) toplev.h output.h \ - $(CPPLIB_H) $(TIMEVAR_H) $(TM_P_H) + $(RTL_H) debug.h $(C_TREE_H) $(C_COMMON_H) real.h c-incpath.h cppdefault.h \ + c-pragma.h input.h intl.h flags.h toplev.h output.h \ + $(CPPLIB_H) $(EXPR_H) $(TM_P_H) c-ppoutput.o : c-ppoutput.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(C_COMMON_H) $(TREE_H) $(CPPLIB_H) $(srcdir)/../libcpp/internal.h \ - $(C_PRAGMA_H) -c-objc-common.o : c-objc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(TREE_H) $(C_TREE_H) $(RTL_H) insn-config.h $(INTEGRATE_H) \ - $(FUNCTION_H) $(FLAGS_H) toplev.h $(TREE_INLINE_H) $(DIAGNOSTIC_H) $(VARRAY_H) \ - langhooks.h $(GGC_H) $(TARGET_H) $(C_PRETTY_PRINT_H) c-objc-common.h \ - tree-mudflap.h + $(C_COMMON_H) $(TREE_H) $(CPPLIB_H) cpphash.h $(TM_P_H) c-pragma.h +c-objc-common.o : c-objc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(C_TREE_H) $(RTL_H) insn-config.h $(INTEGRATE_H) $(EXPR_H) $(C_TREE_H) \ + flags.h toplev.h tree-inline.h $(DIAGNOSTIC_H) $(VARRAY_H) \ + langhooks.h $(GGC_H) $(TARGET_H) cgraph.h c-aux-info.o : c-aux-info.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) $(FLAGS_H) toplev.h -c-convert.o : c-convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(FLAGS_H) toplev.h $(C_COMMON_H) convert.h $(C_TREE_H) \ - langhooks.h $(TARGET_H) -c-pragma.o: c-pragma.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FUNCTION_H) $(C_PRAGMA_H) toplev.h output.h $(GGC_H) $(TM_P_H) \ - $(C_COMMON_H) $(TARGET_H) gt-c-pragma.h $(CPPLIB_H) $(FLAGS_H) -graph.o: graph.c $(SYSTEM_H) coretypes.h $(TM_H) toplev.h $(FLAGS_H) output.h \ - $(RTL_H) $(FUNCTION_H) hard-reg-set.h $(BASIC_BLOCK_H) graph.h $(OBSTACK_H) -sbitmap.o: sbitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FLAGS_H) hard-reg-set.h $(BASIC_BLOCK_H) $(OBSTACK_H) + $(C_TREE_H) flags.h toplev.h +c-convert.o : c-convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + flags.h toplev.h $(C_COMMON_H) real.h +c-pragma.o: c-pragma.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + function.h c-pragma.h toplev.h output.h $(GGC_H) $(TM_P_H) $(C_COMMON_H) gt-c-pragma.h +graph.o: graph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h flags.h output.h \ + $(RTL_H) function.h hard-reg-set.h $(BASIC_BLOCK_H) graph.h +sbitmap.o: sbitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ + hard-reg-set.h $(BASIC_BLOCK_H) COLLECT2_OBJS = collect2.o tlink.o intl.o version.o COLLECT2_LIBS = @COLLECT2_LIBS@ @@ -1639,9 +1359,9 @@ collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS) $(COLLECT2_OBJS) $(LIBS) $(COLLECT2_LIBS) mv -f T$@ $@ -collect2.o : collect2.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) intl.h \ +collect2.o : collect2.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) gstab.h intl.h \ $(OBSTACK_H) $(DEMANGLE_H) collect2.h version.h - $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ -DTARGET_MACHINE=\"$(target_noncanonical)\" \ -c $(srcdir)/collect2.c $(OUTPUT_OPTION) @@ -1651,56 +1371,46 @@ tlink.o: tlink.c $(DEMANGLE_H) $(HASHTAB_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h # A file used by all variants of C. c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(OBSTACK_H) $(C_COMMON_H) $(FLAGS_H) toplev.h output.h $(C_PRAGMA_H) \ + $(OBSTACK_H) $(C_COMMON_H) flags.h toplev.h output.h c-pragma.h intl.h \ $(GGC_H) $(EXPR_H) $(TM_P_H) builtin-types.def builtin-attrs.def \ - $(DIAGNOSTIC_H) gt-c-common.h langhooks.h $(VARRAY_H) $(RTL_H) \ - $(TARGET_H) $(C_TREE_H) tree-iterator.h langhooks.h tree-mudflap.h \ - intl.h opts.h $(REAL_H) $(CPPLIB_H) $(TREE_INLINE_H) $(HASHTAB_H) \ - $(BUILTINS_DEF) - + $(DIAGNOSTIC_H) gt-c-common.h langhooks.h varray.h $(RTL_H) \ + $(TARGET_H) $(C_TREE_H) c-pretty-print.o : c-pretty-print.c $(C_PRETTY_PRINT_H) \ - $(C_TREE_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(REAL_H) \ - $(DIAGNOSTIC_H) tree-iterator.h - -c-opts.o : c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(C_PRAGMA_H) $(FLAGS_H) toplev.h langhooks.h \ - $(TREE_INLINE_H) $(DIAGNOSTIC_H) intl.h debug.h $(C_COMMON_H) \ - opts.h options.h $(MKDEPS_H) c-incpath.h cppdefault.h - $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(C_COMMON_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) real.h + +c-opts.o : c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + c-pragma.h flags.h toplev.h langhooks.h tree-inline.h $(DIAGNOSTIC_H) \ + intl.h debug.h $(C_COMMON_H) opts.h options.h $(PARAMS_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $< $(OUTPUT_OPTION) @TARGET_SYSTEM_ROOT_DEFINE@ c-cppbuiltin.o : c-cppbuiltin.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) version.h $(C_COMMON_H) $(C_PRAGMA_H) $(FLAGS_H) toplev.h \ - output.h except.h $(REAL_H) $(TARGET_H) $(TM_P_H) + $(TREE_H) $(C_COMMON_H) c-pragma.h flags.h toplev.h langhooks.h \ + output.h except.h real.h $(TM_P_H) # A file used by all variants of C and some other languages. -attribs.o : attribs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(FLAGS_H) toplev.h output.h $(RTL_H) $(GGC_H) $(TM_P_H) \ - $(TARGET_H) langhooks.h $(CPPLIB_H) +attribs.o : attribs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) flags.h \ + toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) $(EXPR_H) $(TM_P_H) \ + builtin-types.def $(TARGET_H) langhooks.h c-format.o : c-format.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) langhooks.h \ - $(C_COMMON_H) $(FLAGS_H) toplev.h intl.h $(DIAGNOSTIC_H) c-format.h + $(C_COMMON_H) flags.h toplev.h intl.h $(DIAGNOSTIC_H) -c-semantics.o : c-semantics.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(FLAGS_H) toplev.h output.h $(RTL_H) $(GGC_H) \ - $(PREDICT_H) $(TREE_INLINE_H) $(C_COMMON_H) except.h $(FUNCTION_H) \ - langhooks.h $(SPLAY_TREE_H) $(TIMEVAR_H) $(TREE_GIMPLE_H) \ - $(VARRAY_H) +c-semantics.o : c-semantics.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(C_TREE_H) flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \ + $(EXPR_H) $(PREDICT_H) tree-inline.h c-dump.o : c-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) $(TREE_DUMP_H) + $(C_TREE_H) tree-dump.h c-pch.o : c-pch.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) $(TREE_H) \ - $(C_COMMON_H) output.h toplev.h $(C_PRAGMA_H) $(GGC_H) debug.h \ - langhooks.h $(FLAGS_H) hosthooks.h version.h $(TARGET_H) - $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(C_COMMON_H) output.h toplev.h c-pragma.h $(GGC_H) debug.h \ + langhooks.h flags.h hosthooks.h version.h $(TARGET_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ -DHOST_MACHINE=\"$(host)\" -DTARGET_MACHINE=\"$(target)\" \ $< $(OUTPUT_OPTION) -c-omp.o : c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(FUNCTION_H) $(C_COMMON_H) toplev.h $(TREE_GIMPLE_H) - # Language-independent files. DRIVER_DEFINES = \ @@ -1717,29 +1427,41 @@ DRIVER_DEFINES = \ `test "X$${SHLIB_MULTILIB}" = "X" || echo "-DNO_SHARED_LIBGCC_MULTILIB"` gcc.o: gcc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) intl.h multilib.h \ - Makefile $(lang_specs_files) specs.h prefix.h $(GCC_H) $(FLAGS_H) \ - configargs.h $(OBSTACK_H) opts.h + Makefile $(lang_specs_files) specs.h prefix.h $(GCC_H) (SHLIB_LINK='$(SHLIB_LINK)' \ SHLIB_MULTILIB='$(SHLIB_MULTILIB)'; \ - $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(DRIVER_DEFINES) \ -c $(srcdir)/gcc.c $(OUTPUT_OPTION)) gccspec.o: gccspec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GCC_H) (SHLIB_LINK='$(SHLIB_LINK)' \ SHLIB_MULTILIB='$(SHLIB_MULTILIB)'; \ - $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(DRIVER_DEFINES) \ -c $(srcdir)/gccspec.c $(OUTPUT_OPTION)) cppspec.o: cppspec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GCC_H) +tree-check.h: s-check ; @true +s-check : gencheck$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./gencheck$(build_exeext) > tmp-check.h + $(SHELL) $(srcdir)/move-if-change tmp-check.h tree-check.h + $(STAMP) s-check + +gencheck$(build_exeext) : gencheck.o $(BUILD_LIBDEPS) + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ + gencheck.o $(BUILD_LIBS) + +gencheck.o : gencheck.c gencheck.h tree.def $(BCONFIG_H) $(SYSTEM_H) \ + coretypes.h $(GTM_H) $(lang_tree_files) + gencheck.h : s-gencheck ; @true s-gencheck : Makefile ltf="$(lang_tree_files)"; for f in $$ltf; do \ echo "#include \"$$f\""; \ done | sed 's|$(srcdir)/||' > tmp-gencheck.h - $(SHELL) $(srcdir)/../move-if-change tmp-gencheck.h gencheck.h + $(SHELL) $(srcdir)/move-if-change tmp-gencheck.h gencheck.h $(STAMP) s-gencheck specs.h : s-specs ; @true @@ -1747,926 +1469,425 @@ s-specs : Makefile lsf="$(lang_specs_files)"; for f in $$lsf; do \ echo "#include \"$$f\""; \ done | sed 's|$(srcdir)/||' > tmp-specs.h - $(SHELL) $(srcdir)/../move-if-change tmp-specs.h specs.h + $(SHELL) $(srcdir)/move-if-change tmp-specs.h specs.h $(STAMP) s-specs -optionlist: s-options ; @true -s-options: $(ALL_OPT_FILES) Makefile $(srcdir)/opt-gather.awk - $(AWK) -f $(srcdir)/opt-gather.awk $(ALL_OPT_FILES) > tmp-optionlist - $(SHELL) $(srcdir)/../move-if-change tmp-optionlist optionlist - $(STAMP) s-options - -options.c: optionlist $(srcdir)/opt-functions.awk $(srcdir)/optc-gen.awk - $(AWK) -f $(srcdir)/opt-functions.awk -f $(srcdir)/optc-gen.awk \ - -v header_name="config.h system.h coretypes.h tm.h" < $< > $@ - -options.h: s-options-h ; @true -s-options-h: optionlist $(srcdir)/opt-functions.awk $(srcdir)/opth-gen.awk - $(AWK) -f $(srcdir)/opt-functions.awk -f $(srcdir)/opth-gen.awk \ - < $< > tmp-options.h - $(SHELL) $(srcdir)/../move-if-change tmp-options.h options.h - $(STAMP) $@ +options.c: $(lang_opt_files) $(srcdir)/opts.sh options.h intl.h -options.o: options.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) opts.h intl.h - -gcc-options.o: options.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) opts.h intl.h - $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(OUTPUT_OPTION) -DGCC_DRIVER options.c +options.h: $(lang_opt_files) $(srcdir)/opts.sh Makefile + AWK=$(AWK) $(SHELL) $(srcdir)/opts.sh \ + '$(SHELL) $(srcdir)/move-if-change' \ + options.c options.h $(lang_opt_files) dumpvers: dumpvers.c -version.o: version.c version.h $(DATESTAMP) $(BASEVER) $(DEVPHASE) - $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ - -DBASEVER=$(BASEVER_s) -DDATESTAMP=$(DATESTAMP_s) \ - -DDEVPHASE=$(DEVPHASE_s) -c $(srcdir)/version.c $(OUTPUT_OPTION) +version.o: version.c version.h -gtype-desc.o: gtype-desc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) bitmap.h $(TREE_H) $(RTL_H) \ - $(FUNCTION_H) insn-config.h $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) \ - cselib.h insn-addr.h $(OPTABS_H) libfuncs.h debug.h $(GGC_H) \ - $(CGRAPH_H) $(TREE_FLOW_H) reload.h $(CPP_ID_DATA_H) +gtype-desc.o: gtype-desc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) varray.h \ + $(HASHTAB_H) $(TREE_H) $(RTL_H) function.h insn-config.h $(EXPR_H) $(OPTABS_H) \ + libfuncs.h debug.h $(GGC_H) bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h \ + cselib.h insn-addr.h ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GGC_H) \ - $(HASHTAB_H) toplev.h $(PARAMS_H) hosthooks.h $(HOSTHOOKS_DEF_H) + $(HASHTAB_H) toplev.h $(PARAMS_H) hosthooks.h -ggc-page.o: ggc-page.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ - $(FLAGS_H) toplev.h $(GGC_H) $(TIMEVAR_H) $(TM_P_H) $(PARAMS_H) $(TREE_FLOW_H) +ggc-simple.o: ggc-simple.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h $(GGC_H) varray.h $(TIMEVAR_H) $(TM_P_H) $(PARAMS_H) -ggc-zone.o: ggc-zone.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) toplev.h $(GGC_H) $(TIMEVAR_H) $(TM_P_H) \ - $(PARAMS_H) bitmap.h $(VARRAY_H) +ggc-page.o: ggc-page.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h toplev.h $(GGC_H) $(TIMEVAR_H) $(TM_P_H) $(PARAMS_H) -ggc-none.o: ggc-none.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GGC_H) \ - $(BCONFIG_H) +ggc-zone.o: ggc-zone.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h toplev.h $(GGC_H) $(TIMEVAR_H) $(TM_P_H) $(PARAMS_H) stringpool.o: stringpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(GGC_H) gt-stringpool.h $(CPPLIB_H) $(SYMTAB_H) + $(TREE_H) $(GGC_H) gt-stringpool.h -prefix.o: prefix.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) prefix.h \ - Makefile $(BASEVER) - $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ - -DPREFIX=\"$(prefix)\" -DBASEVER=$(BASEVER_s) \ - -c $(srcdir)/prefix.c $(OUTPUT_OPTION) +ggc-none.o: ggc-none.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) $(GGC_H) + $(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) -convert.o: convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(FLAGS_H) convert.h toplev.h langhooks.h $(REAL_H) +prefix.o: prefix.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) Makefile prefix.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + -DPREFIX=\"$(prefix)\" \ + -c $(srcdir)/prefix.c $(OUTPUT_OPTION) -double-int.o: double-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) +convert.o: convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) flags.h \ + convert.h toplev.h langhooks.h -langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) toplev.h $(TREE_INLINE_H) $(RTL_H) insn-config.h $(INTEGRATE_H) \ - langhooks.h $(LANGHOOKS_DEF_H) $(FLAGS_H) $(GGC_H) $(DIAGNOSTIC_H) intl.h \ - $(TREE_GIMPLE_H) -tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(FLAGS_H) $(FUNCTION_H) $(PARAMS_H) \ +langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) toplev.h \ + tree-inline.h $(RTL_H) insn-config.h $(INTEGRATE_H) langhooks.h \ + $(LANGHOOKS_DEF_H) flags.h $(GGC_H) gt-langhooks.h diagnostic.h +tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) flags.h function.h \ toplev.h $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H) langhooks.h \ - $(REAL_H) gt-tree.h tree-iterator.h $(BASIC_BLOCK_H) $(TREE_FLOW_H) \ - $(OBSTACK_H) pointer-set.h -tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) langhooks.h toplev.h $(SPLAY_TREE_H) $(TREE_DUMP_H) \ - tree-iterator.h tree-pass.h $(DIAGNOSTIC_H) $(REAL_H) + real.h gt-tree.h +tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(C_TREE_H) flags.h langhooks.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \ + $(EXPR_H) $(SPLAY_TREE_H) tree-dump.h tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(RTL_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h insn-config.h \ - $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h \ - langhooks.h $(TREE_INLINE_H) $(CGRAPH_H) intl.h $(FUNCTION_H) $(TREE_GIMPLE_H) \ - debug.h $(DIAGNOSTIC_H) $(TREE_FLOW_H) tree-iterator.h tree-mudflap.h \ - ipa-prop.h + $(TREE_H) $(RTL_H) $(EXPR_H) flags.h $(PARAMS_H) input.h insn-config.h \ + $(INTEGRATE_H) $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h \ + langhooks.h $(C_COMMON_H) tree-inline.h cgraph.h intl.h +tree-optimize.o : tree-optimize.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) toplev.h langhooks.h cgraph.h $(TIMEVAR_H) function.h $(GGC_H) + print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(GGC_H) langhooks.h $(REAL_H) tree-iterator.h -stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(PARAMS_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) $(RTL_H) \ - $(GGC_H) $(TM_P_H) $(TARGET_H) langhooks.h $(REGS_H) gt-stor-layout.h \ - toplev.h -tree-ssa-structalias.o: tree-ssa-structalias.c tree-ssa-structalias.h \ - $(SYSTEM_H) $(CONFIG_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) \ - $(TM_H) coretypes.h $(CGRAPH_H) tree-pass.h $(TIMEVAR_H) \ - gt-tree-ssa-structalias.h $(PARAMS_H) -tree-ssa.o : tree-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) output.h $(DIAGNOSTIC_H) \ - toplev.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ - $(TREE_DUMP_H) langhooks.h tree-pass.h $(BASIC_BLOCK_H) bitmap.h \ - $(FLAGS_H) $(GGC_H) hard-reg-set.h $(HASHTAB_H) pointer-set.h \ - $(TREE_GIMPLE_H) $(TREE_INLINE_H) $(VARRAY_H) -tree-into-ssa.o : tree-into-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) output.h $(DIAGNOSTIC_H) \ - $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - langhooks.h domwalk.h tree-pass.h $(GGC_H) $(PARAMS_H) $(BASIC_BLOCK_H) \ - bitmap.h $(CFGLOOP_H) $(FLAGS_H) hard-reg-set.h $(HASHTAB_H) \ - $(TREE_GIMPLE_H) $(TREE_INLINE_H) $(VARRAY_H) vecprim.h -tree-outof-ssa.o : tree-outof-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) output.h $(DIAGNOSTIC_H) \ - $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - langhooks.h tree-pass.h $(TREE_SSA_LIVE_H) $(BASIC_BLOCK_H) bitmap.h \ - $(FLAGS_H) $(GGC_H) hard-reg-set.h $(HASHTAB_H) $(TREE_GIMPLE_H) \ - $(TREE_INLINE_H) $(VARRAY_H) toplev.h vecprim.h -tree-ssa-dse.o : tree-ssa-dse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(GGC_H) $(TREE_H) $(RTL_H) $(TM_P_H) $(BASIC_BLOCK_H) \ - $(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) domwalk.h $(FLAGS_H) \ - $(DIAGNOSTIC_H) $(TIMEVAR_H) -tree-ssa-forwprop.o : tree-ssa-forwprop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(GGC_H) $(TREE_H) $(RTL_H) $(TM_P_H) $(BASIC_BLOCK_H) \ - $(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \ - langhooks.h -tree-ssa-phiopt.o : tree-ssa-phiopt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(GGC_H) $(TREE_H) $(RTL_H) $(TM_P_H) $(BASIC_BLOCK_H) \ - $(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) langhooks.h $(FLAGS_H) \ - $(DIAGNOSTIC_H) $(TIMEVAR_H) -tree-nrv.o : tree-nrv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(TREE_H) $(RTL_H) $(FUNCTION_H) $(BASIC_BLOCK_H) $(EXPR_H) \ - $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TIMEVAR_H) $(TREE_DUMP_H) tree-pass.h \ + $(GGC_H) langhooks.h real.h +stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + flags.h function.h $(EXPR_H) $(RTL_H) toplev.h $(GGC_H) $(TM_P_H) $(TARGET_H) \ langhooks.h -tree-ssa-copy.o : tree-ssa-copy.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h $(DIAGNOSTIC_H) \ - $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - $(BASIC_BLOCK_H) tree-pass.h langhooks.h tree-ssa-propagate.h $(FLAGS_H) -tree-ssa-propagate.o : tree-ssa-propagate.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \ - $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ - $(TREE_DUMP_H) $(BASIC_BLOCK_H) tree-pass.h langhooks.h \ - tree-ssa-propagate.h vec.h gt-tree-ssa-propagate.h $(FLAGS_H) $(VARRAY_H) -tree-ssa-dom.o : tree-ssa-dom.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h $(DIAGNOSTIC_H) \ - $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - $(BASIC_BLOCK_H) domwalk.h tree-pass.h $(FLAGS_H) langhooks.h \ - tree-ssa-propagate.h $(CFGLOOP_H) $(PARAMS_H) $(REAL_H) -tree-ssa-uncprop.o : tree-ssa-uncprop.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \ - $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ - $(TREE_DUMP_H) $(BASIC_BLOCK_H) domwalk.h tree-pass.h $(FLAGS_H) \ - langhooks.h tree-ssa-propagate.h $(REAL_H) -tree-ssa-threadedge.o : tree-ssa-threadedge.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \ - $(DIAGNOSTIC_H) $(FUNCTION_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - $(BASIC_BLOCK_H) $(FLAGS_H) tree-pass.h $(CFGLOOP_H) -tree-ssa-threadupdate.o : tree-ssa-threadupdate.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \ - $(DIAGNOSTIC_H) $(FUNCTION_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - $(BASIC_BLOCK_H) $(FLAGS_H) tree-pass.h $(CFGLOOP_H) -tree-ssanames.o : tree-ssanames.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(TREE_H) $(VARRAY_H) $(GGC_H) gt-tree-ssanames.h $(TREE_FLOW_H) -tree-phinodes.o : tree-phinodes.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(TREE_H) $(VARRAY_H) $(GGC_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) \ - gt-tree-phinodes.h $(RTL_H) toplev.h -domwalk.o : domwalk.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) domwalk.h $(GGC_H) -tree-ssa-live.o : tree-ssa-live.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(TREE_H) $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) \ - $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_SSA_LIVE_H) $(BASIC_BLOCK_H) \ - bitmap.h $(FLAGS_H) $(HASHTAB_H) $(TREE_GIMPLE_H) $(TREE_INLINE_H) \ - $(VARRAY_H) toplev.h vecprim.h -tree-ssa-copyrename.o : tree-ssa-copyrename.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) tree-pass.h \ - $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_SSA_LIVE_H) $(BASIC_BLOCK_H) \ - bitmap.h $(FLAGS_H) $(HASHTAB_H) langhooks.h $(TREE_GIMPLE_H) \ - $(TREE_INLINE_H) -tree-ssa-pre.o : tree-ssa-pre.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \ - $(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) $(CFGLOOP_H) \ - alloc-pool.h $(BASIC_BLOCK_H) bitmap.h $(HASHTAB_H) $(TREE_GIMPLE_H) \ - $(TREE_INLINE_H) tree-iterator.h -tree-vn.o : tree-vn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GGC_H) \ - $(TREE_H) $(TREE_FLOW_H) $(HASHTAB_H) langhooks.h tree-pass.h \ - $(TREE_DUMP_H) $(DIAGNOSTIC_H) -tree-vrp.o : tree-vrp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(GGC_H) \ - $(BASIC_BLOCK_H) tree-ssa-propagate.h $(FLAGS_H) $(TREE_DUMP_H) \ - $(CFGLOOP_H) $(SCEV_H) tree-chrec.h $(TIMEVAR_H) toplev.h intl.h -tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \ - $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ - $(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \ - $(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h $(HASHTAB_H) toplev.h \ - tree-ssa-propagate.h -tree-cfgcleanup.o : tree-cfgcleanup.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \ - $(DIAGNOSTIC_H) toplev.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ - $(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \ - $(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h $(HASHTAB_H) toplev.h \ - tree-ssa-propagate.h -rtl-factoring.o : rtl-factoring.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ - coretypes.h $(TM_H) $(BASIC_BLOCK_H) $(GGC_H) $(REGS_H) $(PARAMS_H) $(EXPR_H) \ - addresses.h $(TM_P_H) tree-pass.h $(TREE_FLOW_H) $(TIMEVAR_H) output.h -tree-tailcall.o : tree-tailcall.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(FUNCTION_H) $(TM_H) coretypes.h \ - $(TREE_DUMP_H) $(DIAGNOSTIC_H) except.h tree-pass.h $(FLAGS_H) langhooks.h \ - $(BASIC_BLOCK_H) hard-reg-set.h -tree-ssa-sink.o : tree-ssa-sink.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \ - $(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) alloc-pool.h \ - $(BASIC_BLOCK_H) bitmap.h $(CFGLOOP_H) $(FIBHEAP_H) $(HASHTAB_H) \ - langhooks.h $(REAL_H) $(TREE_GIMPLE_H) $(TREE_INLINE_H) tree-iterator.h -tree-nested.o: tree-nested.c $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(TREE_H) \ - $(RTL_H) $(TM_P_H) $(FUNCTION_H) $(TREE_DUMP_H) $(TREE_INLINE_H) \ - tree-iterator.h $(TREE_GIMPLE_H) $(CGRAPH_H) $(EXPR_H) langhooks.h \ - $(GGC_H) gt-tree-nested.h coretypes.h $(TREE_FLOW_H) -tree-if-conv.o: tree-if-conv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(FLAGS_H) $(TIMEVAR_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) \ - $(CFGLOOP_H) $(RTL_H) $(C_COMMON_H) tree-chrec.h $(TREE_DATA_REF_H) \ - $(SCEV_H) tree-pass.h $(DIAGNOSTIC_H) $(TARGET_H) $(TREE_DUMP_H) \ - $(VARRAY_H) -tree-iterator.o : tree-iterator.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ - coretypes.h $(GGC_H) tree-iterator.h $(TREE_GIMPLE_H) gt-tree-iterator.h -tree-dfa.o : tree-dfa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h $(DIAGNOSTIC_H) \ - $(TREE_INLINE_H) $(HASHTAB_H) pointer-set.h $(FLAGS_H) $(FUNCTION_H) \ - $(TIMEVAR_H) convert.h $(TM_H) coretypes.h langhooks.h $(TREE_DUMP_H) \ - tree-pass.h $(PARAMS_H) $(CGRAPH_H) $(BASIC_BLOCK_H) hard-reg-set.h \ - $(TREE_GIMPLE_H) -tree-ssa-operands.o : tree-ssa-operands.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) errors.h $(TREE_INLINE_H) \ - $(FLAGS_H) $(FUNCTION_H) $(TM_H) $(TIMEVAR_H) tree-pass.h toplev.h \ - gt-tree-ssa-operands.h coretypes.h langhooks.h $(IPA_REFERENCE_H) -tree-eh.o : tree-eh.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_H) $(FLAGS_H) $(FUNCTION_H) except.h langhooks.h \ - $(GGC_H) tree-pass.h coretypes.h $(TIMEVAR_H) $(TM_P_H) \ - $(TREE_DUMP_H) $(TREE_INLINE_H) tree-iterator.h toplev.h -tree-ssa-loop.o : tree-ssa-loop.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) \ - output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - tree-pass.h $(FLAGS_H) $(TREE_INLINE_H) $(SCEV_H) $(BASIC_BLOCK_H) \ - hard-reg-set.h -tree-ssa-loop-unswitch.o : tree-ssa-loop-unswitch.c $(TREE_FLOW_H) \ - $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) \ - domwalk.h $(PARAMS_H) output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) \ - coretypes.h $(TREE_DUMP_H) tree-pass.h $(BASIC_BLOCK_H) hard-reg-set.h -tree-ssa-address.o : tree-ssa-address.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) \ - output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - tree-pass.h $(FLAGS_H) $(TREE_INLINE_H) $(RECOG_H) insn-config.h $(EXPR_H) \ - gt-tree-ssa-address.h $(GGC_H) -tree-ssa-loop-niter.o : tree-ssa-loop-niter.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) $(PARAMS_H) \ - $(TREE_INLINE_H) output.h $(DIAGNOSTIC_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - $(FLAGS_H) tree-pass.h $(SCEV_H) $(TREE_DATA_REF_H) $(BASIC_BLOCK_H) \ - $(GGC_H) hard-reg-set.h tree-chrec.h intl.h -tree-ssa-loop-ivcanon.o : tree-ssa-loop-ivcanon.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) $(PARAMS_H) \ - $(TREE_INLINE_H) output.h $(DIAGNOSTIC_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - $(FLAGS_H) tree-pass.h $(SCEV_H) $(BASIC_BLOCK_H) $(GGC_H) hard-reg-set.h \ - tree-chrec.h -tree-ssa-loop-ch.o : tree-ssa-loop-ch.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) $(TREE_INLINE_H) \ - output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - tree-pass.h $(FLAGS_H) $(BASIC_BLOCK_H) hard-reg-set.h -tree-ssa-loop-prefetch.o: tree-ssa-loop-prefetch.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) $(EXPR_H) \ - output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - tree-pass.h $(GGC_H) $(RECOG_H) insn-config.h $(HASHTAB_H) $(SCEV_H) \ - $(CFGLOOP_H) $(PARAMS_H) langhooks.h $(BASIC_BLOCK_H) hard-reg-set.h \ - tree-chrec.h toplev.h langhooks.h -tree-ssa-loop-ivopts.o : tree-ssa-loop-ivopts.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) $(EXPR_H) \ - output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - tree-pass.h $(GGC_H) $(RECOG_H) insn-config.h $(HASHTAB_H) $(SCEV_H) \ - $(CFGLOOP_H) $(PARAMS_H) langhooks.h $(BASIC_BLOCK_H) hard-reg-set.h \ - tree-chrec.h $(VARRAY_H) -tree-ssa-loop-manip.o : tree-ssa-loop-manip.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) \ - output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ - tree-pass.h $(CFGLAYOUT_H) $(SCEV_H) $(BASIC_BLOCK_H) hard-reg-set.h \ - $(PARAMS_H) -tree-ssa-loop-im.o : tree-ssa-loop-im.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) domwalk.h \ - $(PARAMS_H) output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ - $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) $(REAL_H) $(BASIC_BLOCK_H) \ - hard-reg-set.h -tree-ssa-math-opts.o : tree-ssa-math-opts.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(TREE_H) $(TIMEVAR_H) tree-pass.h $(TM_H) $(FLAGS_H) \ - alloc-pool.h $(BASIC_BLOCK_H) $(TARGET_H) -tree-ssa-alias.o : tree-ssa-alias.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(TREE_INLINE_H) $(FLAGS_H) \ - $(FUNCTION_H) $(TIMEVAR_H) convert.h $(TM_H) coretypes.h langhooks.h \ - $(TREE_DUMP_H) tree-pass.h $(PARAMS_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) \ - hard-reg-set.h $(TREE_GIMPLE_H) vec.h tree-ssa-structalias.h \ - $(IPA_TYPE_ESCAPE_H) vecprim.h pointer-set.h -tree-ssa-reassoc.o : tree-ssa-reassoc.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) errors.h $(TIMEVAR_H) \ - $(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) tree-iterator.h\ - $(BASIC_BLOCK_H) $(TREE_GIMPLE_H) $(TREE_INLINE_H) vec.h \ - alloc-pool.h -tree-optimize.o : tree-optimize.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h $(DIAGNOSTIC_H) \ - $(FLAGS_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) toplev.h \ - $(FUNCTION_H) langhooks.h $(FLAGS_H) $(CGRAPH_H) $(TREE_INLINE_H) \ - tree-mudflap.h $(GGC_H) $(CGRAPH_H) tree-pass.h $(CFGLOOP_H) \ - $(BASIC_BLOCK_H) graph.h hard-reg-set.h -c-gimplify.o : c-gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ - $(C_TREE_H) $(C_COMMON_H) $(DIAGNOSTIC_H) $(TREE_GIMPLE_H) $(VARRAY_H) \ - $(FLAGS_H) langhooks.h toplev.h $(RTL_H) $(TREE_FLOW_H) $(LANGHOOKS_DEF_H) \ - $(TM_H) coretypes.h $(C_PRETTY_PRINT_H) $(CGRAPH_H) $(BASIC_BLOCK_H) \ - hard-reg-set.h $(TREE_DUMP_H) $(TREE_INLINE_H) -gimplify.o : gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ - $(DIAGNOSTIC_H) $(TREE_GIMPLE_H) $(TREE_INLINE_H) $(VARRAY_H) langhooks.h \ - $(LANGHOOKS_DEF_H) $(TREE_FLOW_H) $(CGRAPH_H) $(TIMEVAR_H) $(TM_H) \ - coretypes.h except.h $(FLAGS_H) $(RTL_H) $(FUNCTION_H) $(EXPR_H) output.h \ - $(GGC_H) gt-gimplify.h $(HASHTAB_H) $(TARGET_H) toplev.h $(OPTABS_H) \ - $(REAL_H) -gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ - $(DIAGNOSTIC_H) $(TREE_GIMPLE_H) $(TREE_INLINE_H) $(VARRAY_H) langhooks.h \ - $(LANGHOOKS_DEF_H) $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ - except.h $(FLAGS_H) $(RTL_H) $(FUNCTION_H) $(EXPR_H) tree-pass.h \ - $(HASHTAB_H) toplev.h -omp-low.o : omp-low.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(RTL_H) $(TREE_GIMPLE_H) $(TREE_INLINE_H) langhooks.h $(DIAGNOSTIC_H) \ - $(TREE_FLOW_H) $(TIMEVAR_H) $(FLAGS_H) $(EXPR_H) toplev.h tree-pass.h \ - $(GGC_H) -tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \ - $(TREE_H) $(TREE_INLINE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) \ - $(TM_H) coretypes.h -tree-chrec.o: tree-chrec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(GGC_H) $(TREE_H) $(REAL_H) $(SCEV_H) tree-pass.h $(PARAMS_H) \ - $(DIAGNOSTIC_H) $(CFGLOOP_H) $(TREE_FLOW_H) -tree-scalar-evolution.o: tree-scalar-evolution.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(GGC_H) $(TREE_H) $(REAL_H) $(RTL_H) \ - $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) \ - $(TIMEVAR_H) $(CFGLOOP_H) $(SCEV_H) tree-pass.h $(FLAGS_H) tree-chrec.h -tree-data-ref.o: tree-data-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(GGC_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) \ - $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \ - $(TREE_DATA_REF_H) $(SCEV_H) tree-pass.h tree-chrec.h -tree-vect-analyze.o: tree-vect-analyze.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(GGC_H) $(OPTABS_H) $(TREE_H) $(BASIC_BLOCK_H) \ - $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \ - tree-vectorizer.h $(TREE_DATA_REF_H) $(SCEV_H) $(EXPR_H) tree-chrec.h -tree-vect-patterns.o: tree-vect-patterns.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) errors.h $(GGC_H) $(OPTABS_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) \ - $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \ - tree-vectorizer.h $(TREE_DATA_REF_H) $(EXPR_H) $(TARGET_H) -tree-vect-transform.o: tree-vect-transform.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(GGC_H) $(OPTABS_H) $(RECOG_H) $(TREE_H) $(RTL_H) \ - $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) \ - $(TIMEVAR_H) $(CFGLOOP_H) $(TARGET_H) tree-pass.h $(EXPR_H) \ - tree-vectorizer.h $(TREE_DATA_REF_H) $(SCEV_H) langhooks.h toplev.h \ - tree-chrec.h -tree-vectorizer.o: tree-vectorizer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(GGC_H) $(OPTABS_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) \ - $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \ - tree-pass.h $(EXPR_H) tree-vectorizer.h $(TREE_DATA_REF_H) $(SCEV_H) \ - input.h $(TARGET_H) $(CFGLAYOUT_H) toplev.h tree-chrec.h -tree-loop-linear.o: tree-loop-linear.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(GGC_H) $(OPTABS_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) \ - $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \ - tree-pass.h $(TREE_DATA_REF_H) $(SCEV_H) $(EXPR_H) $(LAMBDA_H) \ - $(TARGET_H) tree-chrec.h -tree-stdarg.o: tree-stdarg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(FUNCTION_H) $(DIAGNOSTIC_H) $(TREE_FLOW_H) tree-pass.h \ - tree-stdarg.h $(TARGET_H) langhooks.h -tree-object-size.o: tree-object-size.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(TREE_H) $(DIAGNOSTIC_H) $(TREE_FLOW_H) tree-pass.h \ - tree-ssa-propagate.h -tree-gimple.o : tree-gimple.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(EXPR_H) \ - $(RTL_H) $(TREE_GIMPLE_H) $(TM_H) coretypes.h bitmap.h $(GGC_H) \ - output.h $(TREE_FLOW_H) -tree-mudflap.o : $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TREE_INLINE_H) \ - $(TREE_GIMPLE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) langhooks.h tree-mudflap.h \ - $(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(CGRAPH_H) $(GGC_H) \ - gt-tree-mudflap.h $(BASIC_BLOCK_H) $(FLAGS_H) $(FUNCTION_H) hard-reg-set.h \ - $(RTL_H) $(TM_P_H) $(TREE_FLOW_H) toplev.h -tree-nomudflap.o : $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TREE_INLINE_H) \ - $(C_TREE_H) $(C_COMMON_H) $(TREE_GIMPLE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) \ - output.h $(VARRAY_H) langhooks.h tree-mudflap.h $(TM_H) coretypes.h \ - $(GGC_H) gt-tree-mudflap.h tree-pass.h toplev.h -tree-pretty-print.o : tree-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \ - $(TREE_H) $(DIAGNOSTIC_H) $(REAL_H) $(HASHTAB_H) $(TREE_FLOW_H) \ - $(TM_H) coretypes.h tree-iterator.h tree-chrec.h langhooks.h tree-pass.h -fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(FLAGS_H) $(REAL_H) toplev.h $(HASHTAB_H) $(EXPR_H) $(RTL_H) \ - $(GGC_H) $(TM_P_H) langhooks.h $(MD5_H) intl.h -diagnostic.o : diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) version.h $(TM_P_H) $(FLAGS_H) input.h toplev.h intl.h \ - $(DIAGNOSTIC_H) langhooks.h $(LANGHOOKS_DEF_H) diagnostic.def opts.h +fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + flags.h real.h toplev.h $(HASHTAB_H) $(EXPR_H) $(RTL_H) $(GGC_H) $(TM_P_H) langhooks.h +diagnostic.o : diagnostic.c $(DIAGNOSTIC_H) real.h \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(TM_P_H) flags.h $(GGC_H) \ + input.h toplev.h intl.h langhooks.h $(LANGHOOKS_DEF_H) opts.o : opts.c opts.h options.h toplev.h $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TREE_H) $(TM_H) langhooks.h $(GGC_H) $(RTL_H) \ - output.h $(DIAGNOSTIC_H) $(TM_P_H) $(INSN_ATTR_H) intl.h $(TARGET_H) \ - $(FLAGS_H) $(PARAMS_H) tree-pass.h -opts-common.o : opts-common.c opts.h $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h intl.h -targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ - $(EXPR_H) $(TM_H) $(RTL_H) $(TM_P_H) $(FUNCTION_H) output.h toplev.h \ - $(MACHMODE_H) $(TARGET_DEF_H) $(TARGET_H) $(GGC_H) gt-targhooks.h - -toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - version.h $(RTL_H) $(FUNCTION_H) $(FLAGS_H) xcoffout.h input.h \ - $(INSN_ATTR_H) output.h $(DIAGNOSTIC_H) debug.h insn-config.h intl.h \ - $(RECOG_H) Makefile toplev.h dwarf2out.h sdbout.h dbxout.h $(EXPR_H) \ - hard-reg-set.h $(BASIC_BLOCK_H) graph.h except.h $(REGS_H) $(TIMEVAR_H) \ - value-prof.h $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \ - langhooks.h insn-flags.h $(CFGLAYOUT_H) $(CFGLOOP_H) hosthooks.h \ - $(CGRAPH_H) $(COVERAGE_H) alloc-pool.h $(GGC_H) $(INTEGRATE_H) \ - $(CPPLIB_H) opts.h params.def tree-mudflap.h $(REAL_H) - $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ - -DTARGET_NAME=\"$(target_noncanonical)\" \ - -c $(srcdir)/toplev.c $(OUTPUT_OPTION) - -passes.o : passes.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(RTL_H) $(FUNCTION_H) $(FLAGS_H) xcoffout.h input.h $(INSN_ATTR_H) output.h \ - $(DIAGNOSTIC_H) debug.h insn-config.h intl.h $(RECOG_H) toplev.h \ + coretypes.h $(TREE_H) $(TM_H) langhooks.h $(GGC_H) $(RTL_H) \ + output.h $(DIAGNOSTIC_H) $(TM_P_H) $(INSN_ATTR_H) intl.h +targhooks.o : targhooks.c targhooks.h $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TREE_H) $(TM_H) $(RTL_H) $(TM_P_H) function.h \ + output.h toplev.h + +toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ + function.h flags.h xcoffout.h input.h $(INSN_ATTR_H) output.h $(DIAGNOSTIC_H) \ + debug.h insn-config.h intl.h $(RECOG_H) Makefile toplev.h \ dwarf2out.h sdbout.h dbxout.h $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) \ - graph.h except.h $(REGS_H) $(TIMEVAR_H) value-prof.h \ + graph.h $(LOOP_H) except.h $(REGS_H) $(TIMEVAR_H) value-prof.h \ $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \ - langhooks.h insn-flags.h $(CFGLAYOUT_H) $(REAL_H) $(CFGLOOP_H) \ - hosthooks.h $(CGRAPH_H) $(COVERAGE_H) tree-pass.h $(TREE_DUMP_H) \ - $(GGC_H) $(INTEGRATE_H) $(CPPLIB_H) opts.h $(TREE_FLOW_H) $(TREE_INLINE_H) - + langhooks.h insn-flags.h cfglayout.h real.h cfgloop.h \ + hosthooks.h $(LANGHOOKS_DEF_H) cgraph.h $(COVERAGE_H) alloc-pool.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + -DTARGET_NAME=\"$(target_noncanonical)\" \ + -c $(srcdir)/toplev.c $(OUTPUT_OPTION) main.o : main.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h host-default.o : host-default.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - hosthooks.h $(HOSTHOOKS_DEF_H) + hosthooks.h hosthooks-def.h -rtl-error.o: rtl-error.c $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(INSN_ATTR_H) insn-config.h input.h toplev.h intl.h $(DIAGNOSTIC_H) \ - $(CONFIG_H) +rtl-error.o: rtl-error.c $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(INSN_ATTR_H) \ + insn-config.h input.h toplev.h intl.h $(DIAGNOSTIC_H) $(CONFIG_H) -rtl.o : rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(GGC_H) $(BCONFIG_H) insn-notes.def reg-notes.def toplev.h $(REAL_H) +rtl.o : rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) $(RTL_H) real.h \ + $(GGC_H) errors.h + $(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) print-rtl.o : print-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) $(FLAGS_H) \ - $(BCONFIG_H) $(REAL_H) + $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) real.h $(TM_P_H) rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h \ - $(RTL_H) hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) $(REAL_H) \ - $(FLAGS_H) $(REGS_H) output.h $(TARGET_H) $(FUNCTION_H) - -varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(RTL_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) hard-reg-set.h $(REGS_H) \ - output.h $(C_PRAGMA_H) toplev.h xcoffout.h debug.h $(GGC_H) $(TM_P_H) \ - $(HASHTAB_H) $(TARGET_H) langhooks.h gt-varasm.h $(BASIC_BLOCK_H) \ - $(CFGLAYOUT_H) $(CGRAPH_H) tree-mudflap.h $(REAL_H) -function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(CFGLAYOUT_H) $(TREE_GIMPLE_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) \ - $(OPTABS_H) libfuncs.h $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) \ - output.h toplev.h except.h $(HASHTAB_H) $(GGC_H) $(TM_P_H) langhooks.h \ - gt-function.h $(TARGET_H) $(BASIC_BLOCK_H) $(INTEGRATE_H) $(PREDICT_H) \ - tree-pass.h vecprim.h -stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) $(FUNCTION_H) insn-config.h hard-reg-set.h $(EXPR_H) \ - libfuncs.h except.h $(RECOG_H) toplev.h output.h $(GGC_H) $(TM_P_H) \ - langhooks.h $(PREDICT_H) $(OPTABS_H) $(TARGET_H) $(MACHMODE_H) \ - $(REGS_H) + $(RTL_H) hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) real.h flags.h \ + $(BASIC_BLOCK_H) + +errors.o : errors.c $(CONFIG_H) $(SYSTEM_H) errors.h + $(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ + flags.h function.h $(EXPR_H) hard-reg-set.h $(REGS_H) \ + output.h c-pragma.h toplev.h xcoffout.h debug.h $(GGC_H) $(TM_P_H) \ + $(HASHTAB_H) $(TARGET_H) langhooks.h gt-varasm.h real.h +function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h function.h $(EXPR_H) $(OPTABS_H) libfuncs.h $(REGS_H) hard-reg-set.h \ + insn-config.h $(RECOG_H) output.h toplev.h except.h $(HASHTAB_H) $(GGC_H) \ + $(TM_P_H) langhooks.h gt-function.h $(TARGET_H) +stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) flags.h \ + function.h insn-config.h hard-reg-set.h $(EXPR_H) libfuncs.h except.h \ + $(LOOP_H) $(RECOG_H) toplev.h output.h varray.h $(GGC_H) $(TM_P_H) \ + langhooks.h $(PREDICT_H) gt-stmt.h $(OPTABS_H) $(TARGET_H) except.o : except.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) except.h $(FUNCTION_H) $(EXPR_H) libfuncs.h \ + $(TREE_H) flags.h except.h function.h $(EXPR_H) libfuncs.h $(INTEGRATE_H) \ langhooks.h insn-config.h hard-reg-set.h $(BASIC_BLOCK_H) output.h \ dwarf2asm.h dwarf2out.h toplev.h $(HASHTAB_H) intl.h $(GGC_H) \ - gt-except.h $(CGRAPH_H) $(INTEGRATE_H) $(DIAGNOSTIC_H) dwarf2.h \ - $(TARGET_H) $(TM_P_H) tree-pass.h $(TIMEVAR_H) -expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) $(EXPR_H) $(OPTABS_H) \ - libfuncs.h $(INSN_ATTR_H) insn-config.h $(RECOG_H) output.h \ - typeclass.h hard-reg-set.h toplev.h hard-reg-set.h except.h reload.h \ - $(GGC_H) langhooks.h intl.h $(TM_P_H) $(REAL_H) $(TARGET_H) \ - tree-iterator.h gt-expr.h $(MACHMODE_H) $(TIMEVAR_H) $(TREE_FLOW_H) \ - tree-pass.h + gt-except.h cgraph.h +expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) flags.h \ + function.h $(REGS_H) $(EXPR_H) $(OPTABS_H) libfuncs.h $(INSN_ATTR_H) insn-config.h \ + $(RECOG_H) output.h typeclass.h hard-reg-set.h toplev.h hard-reg-set.h \ + except.h reload.h $(GGC_H) langhooks.h intl.h $(TM_P_H) real.h $(TARGET_H) dojump.o : dojump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ - $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) $(OPTABS_H) $(INSN_ATTR_H) insn-config.h \ + flags.h function.h $(EXPR_H) $(OPTABS_H) $(INSN_ATTR_H) insn-config.h \ langhooks.h $(GGC_H) gt-dojump.h -builtins.o : builtins.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(TREE_GIMPLE_H) $(FLAGS_H) $(TARGET_H) $(FUNCTION_H) $(REGS_H) \ - $(EXPR_H) $(OPTABS_H) insn-config.h $(RECOG_H) output.h typeclass.h \ - hard-reg-set.h toplev.h hard-reg-set.h except.h $(TM_P_H) $(PREDICT_H) \ - libfuncs.h $(REAL_H) langhooks.h $(BASIC_BLOCK_H) tree-mudflap.h \ - $(BUILTINS_DEF) $(MACHMODE_H) -calls.o : calls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) $(EXPR_H) $(OPTABS_H) langhooks.h $(TARGET_H) \ - libfuncs.h $(REGS_H) toplev.h output.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_P_H) \ - $(CGRAPH_H) except.h sbitmap.h +builtins.o : builtins.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H)\ + flags.h $(TARGET_H) function.h $(REGS_H) $(EXPR_H) $(OPTABS_H) insn-config.h \ + $(RECOG_H) output.h typeclass.h hard-reg-set.h toplev.h hard-reg-set.h \ + except.h $(TM_P_H) $(PREDICT_H) libfuncs.h real.h langhooks.h +calls.o : calls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) flags.h \ + $(EXPR_H) $(OPTABS_H) langhooks.h $(TARGET_H) \ + libfuncs.h $(REGS_H) toplev.h output.h function.h $(TIMEVAR_H) $(TM_P_H) cgraph.h except.h expmed.o : expmed.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ - $(FLAGS_H) insn-config.h $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(REAL_H) \ + flags.h insn-config.h $(EXPR_H) $(OPTABS_H) $(RECOG_H) real.h \ toplev.h $(TM_P_H) langhooks.h explow.o : explow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ - $(FLAGS_H) hard-reg-set.h insn-config.h $(EXPR_H) $(OPTABS_H) $(RECOG_H) \ - toplev.h $(FUNCTION_H) $(GGC_H) $(TM_P_H) langhooks.h gt-explow.h \ - $(TARGET_H) output.h -optabs.o : optabs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) insn-config.h $(EXPR_H) $(OPTABS_H) libfuncs.h \ - $(RECOG_H) reload.h toplev.h $(GGC_H) $(REAL_H) $(TM_P_H) except.h \ - gt-optabs.h $(BASIC_BLOCK_H) $(TARGET_H) $(FUNCTION_H) -dbxout.o : dbxout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(RTL_H) $(FLAGS_H) $(REGS_H) debug.h $(TM_P_H) $(TARGET_H) $(FUNCTION_H) \ - langhooks.h insn-config.h reload.h gstab.h xcoffout.h output.h dbxout.h \ - toplev.h $(GGC_H) $(OBSTACK_H) $(EXPR_H) gt-dbxout.h + flags.h hard-reg-set.h insn-config.h $(EXPR_H) $(OPTABS_H) $(RECOG_H) \ + toplev.h function.h $(GGC_H) $(TM_P_H) langhooks.h gt-explow.h +optabs.o : optabs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h insn-config.h $(EXPR_H) $(OPTABS_H) libfuncs.h $(RECOG_H) reload.h \ + toplev.h $(GGC_H) real.h $(TM_P_H) except.h gt-optabs.h $(BASIC_BLOCK_H) \ + $(TARGET_H) +dbxout.o : dbxout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ + flags.h $(REGS_H) debug.h $(TM_P_H) $(TARGET_H) function.h langhooks.h \ + insn-config.h reload.h gstab.h xcoffout.h output.h dbxout.h toplev.h \ + $(GGC_H) gt-dbxout.h debug.o : debug.c debug.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) -sdbout.o : sdbout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) debug.h \ - $(TREE_H) $(GGC_H) $(RTL_H) $(REGS_H) $(FLAGS_H) insn-config.h \ - output.h toplev.h $(TM_P_H) gsyms.h langhooks.h $(TARGET_H) sdbout.h \ - gt-sdbout.h reload.h $(VARRAY_H) -dwarf2out.o : dwarf2out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) version.h $(RTL_H) dwarf2.h debug.h $(FLAGS_H) insn-config.h \ - output.h $(DIAGNOSTIC_H) $(REAL_H) hard-reg-set.h $(REGS_H) $(EXPR_H) \ - libfuncs.h toplev.h dwarf2out.h reload.h $(GGC_H) except.h dwarf2asm.h \ - $(TM_P_H) langhooks.h $(HASHTAB_H) gt-dwarf2out.h $(TARGET_H) $(CGRAPH_H) \ - $(MD5_H) input.h $(FUNCTION_H) $(VARRAY_H) -dwarf2asm.o : dwarf2asm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(FLAGS_H) $(RTL_H) $(TREE_H) output.h dwarf2asm.h $(TM_P_H) $(GGC_H) \ - gt-dwarf2asm.h dwarf2.h $(SPLAY_TREE_H) $(TARGET_H) -vmsdbgout.o : vmsdbgout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) version.h \ - $(RTL_H) $(FLAGS_H) output.h vmsdbg.h debug.h langhooks.h $(FUNCTION_H) $(TARGET_H) -xcoffout.o : xcoffout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) $(RTL_H) xcoffout.h $(FLAGS_H) toplev.h output.h dbxout.h \ - $(GGC_H) $(TARGET_H) gstab.h xcoff.h -emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) insn-config.h $(RECOG_H) \ - $(GGC_H) $(EXPR_H) hard-reg-set.h bitmap.h toplev.h $(BASIC_BLOCK_H) \ - $(HASHTAB_H) $(TM_P_H) debug.h langhooks.h tree-pass.h gt-emit-rtl.h \ - $(REAL_H) -real.o : real.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - toplev.h $(TM_P_H) $(REAL_H) -dfp.o : dfp.c dfp.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - toplev.h $(TM_P_H) $(REAL_H) $(DECNUM_H) -integrate.o : integrate.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(TREE_H) $(FLAGS_H) debug.h $(INTEGRATE_H) insn-config.h \ - $(EXPR_H) $(REAL_H) $(REGS_H) intl.h $(FUNCTION_H) output.h $(RECOG_H) \ - except.h toplev.h $(PARAMS_H) $(TM_P_H) $(TARGET_H) langhooks.h \ - gt-integrate.h $(GGC_H) tree-pass.h -jump.o : jump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FLAGS_H) hard-reg-set.h $(REGS_H) insn-config.h $(RECOG_H) $(EXPR_H) \ - $(REAL_H) except.h $(FUNCTION_H) tree-pass.h $(DIAGNOSTIC_H) \ - toplev.h $(INSN_ATTR_H) $(TM_P_H) reload.h $(PREDICT_H) \ - $(TIMEVAR_H) $(TARGET_H) -simplify-rtx.o : simplify-rtx.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) $(REAL_H) insn-config.h \ - $(RECOG_H) $(EXPR_H) toplev.h output.h $(FUNCTION_H) $(GGC_H) $(TM_P_H) \ - $(TREE_H) $(TARGET_H) +sdbout.o : sdbout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ + flags.h function.h $(EXPR_H) output.h hard-reg-set.h $(REGS_H) real.h \ + insn-config.h xcoffout.h c-pragma.h $(GGC_H) $(TARGET_H) \ + sdbout.h toplev.h $(TM_P_H) except.h debug.h langhooks.h gt-sdbout.h +dwarf2out.o : dwarf2out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(RTL_H) dwarf2.h debug.h flags.h insn-config.h reload.h output.h $(DIAGNOSTIC_H) real.h \ + hard-reg-set.h $(REGS_H) $(EXPR_H) libfuncs.h toplev.h dwarf2out.h varray.h \ + $(GGC_H) except.h dwarf2asm.h $(TM_P_H) langhooks.h $(HASHTAB_H) \ + gt-dwarf2out.h $(TARGET_H) cgraph.h +dwarf2asm.o : dwarf2asm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) flags.h $(RTL_H) \ + $(TREE_H) output.h dwarf2asm.h $(TM_P_H) $(GGC_H) gt-dwarf2asm.h +vmsdbgout.o : vmsdbgout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(RTL_H) flags.h output.h vmsdbg.h debug.h langhooks.h function.h $(TARGET_H) +xcoffout.o : xcoffout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ + xcoffout.h flags.h toplev.h output.h dbxout.h $(GGC_H) $(TARGET_H) +emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h function.h $(REGS_H) insn-config.h $(RECOG_H) real.h $(GGC_H) \ + $(EXPR_H) $(OBSTACK_H) hard-reg-set.h bitmap.h toplev.h \ + $(HASHTAB_H) $(TM_P_H) debug.h langhooks.h gt-emit-rtl.h +real.o : real.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) toplev.h $(TM_P_H) +integrate.o : integrate.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h debug.h $(INTEGRATE_H) insn-config.h $(EXPR_H) real.h $(REGS_H) \ + intl.h function.h output.h $(RECOG_H) except.h toplev.h $(LOOP_H) \ + $(PARAMS_H) $(TM_P_H) $(TARGET_H) langhooks.h gt-integrate.h +jump.o : jump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ + hard-reg-set.h $(REGS_H) insn-config.h $(RECOG_H) $(EXPR_H) real.h except.h function.h \ + toplev.h $(INSN_ATTR_H) $(TM_P_H) reload.h $(PREDICT_H) $(TIMEVAR_H) \ + $(DIAGNOSTIC_H) + +simplify-rtx.o : simplify-rtx.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + $(REGS_H) hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \ + output.h function.h $(GGC_H) $(OBSTACK_H) $(TM_P_H) $(TREE_H) $(TARGET_H) cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - langhooks.h toplev.h $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \ - gt-cgraph.h output.h intl.h $(BASIC_BLOCK_H) debug.h $(HASHTAB_H) \ - $(TREE_INLINE_H) $(VARRAY_H) $(TREE_DUMP_H) -cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) langhooks.h $(TREE_INLINE_H) toplev.h $(FLAGS_H) $(GGC_H) \ - $(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(TREE_GIMPLE_H) \ - $(TREE_FLOW_H) tree-pass.h $(C_COMMON_H) debug.h $(DIAGNOSTIC_H) \ - $(FIBHEAP_H) output.h $(PARAMS_H) $(RTL_H) $(TIMEVAR_H) ipa-prop.h \ - gt-cgraphunit.h -ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) -ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) ipa-prop.h \ - $(TREE_FLOW_H) $(TM_H) tree-pass.h $(FLAGS_H) $(TREE_H) -ipa-cp.o : ipa-cp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - langhooks.h $(TARGET_H) $(CGRAPH_H) ipa-prop.h \ - $(TREE_FLOW_H) $(TM_H) tree-pass.h $(FLAGS_H) $(TREE_H) $(DIAGNOSTIC_H) -ipa-inline.o : ipa-inline.c gt-ipa-inline.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) langhooks.h $(TREE_INLINE_H) $(FLAGS_H) $(CGRAPH_H) intl.h \ - $(DIAGNOSTIC_H) $(FIBHEAP_H) $(PARAMS_H) $(TIMEVAR_H) tree-pass.h \ - $(COVERAGE_H) $(HASHTAB_H) -ipa-utils.o : ipa-utils.c $(IPA_UTILS_H) $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \ - pointer-set.h $(GGC_H) $(C_COMMON_H) $(TREE_GIMPLE_H) \ - $(CGRAPH_H) output.h $(FLAGS_H) tree-pass.h $(DIAGNOSTIC_H) -ipa-reference.o : ipa-reference.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \ - pointer-set.h $(GGC_H) $(IPA_REFERENCE_H) $(IPA_UTILS_H) $(C_COMMON_H) \ - $(TREE_GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) tree-pass.h \ - $(DIAGNOSTIC_H) $(FUNCTION_H) - -ipa-pure-const.o : ipa-pure-const.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \ - pointer-set.h $(GGC_H) $(IPA_UTILS_H) $(C_COMMON_H) $(TARGET_H) \ - $(TREE_GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) tree-pass.h $(DIAGNOSTIC_H) -ipa-type-escape.o : ipa-type-escape.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \ - pointer-set.h $(GGC_H) $(IPA_TYPE_ESCAPE_H) $(IPA_UTILS_H) $(C_COMMON_H) \ - $(TREE_GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) tree-pass.h \ - $(DIAGNOSTIC_H) $(FUNCTION_H) - -coverage.o : coverage.c $(GCOV_IO_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) \ - $(FUNCTION_H) toplev.h $(GGC_H) langhooks.h $(COVERAGE_H) gt-coverage.h \ - $(HASHTAB_H) $(CGRAPH_H) tree-iterator.h -cselib.o : cselib.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(REGS_H) hard-reg-set.h $(FLAGS_H) $(REAL_H) insn-config.h $(RECOG_H) \ - $(EMIT_RTL_H) toplev.h output.h $(FUNCTION_H) cselib.h $(GGC_H) $(TM_P_H) \ - gt-cselib.h $(PARAMS_H) alloc-pool.h $(HASHTAB_H) $(TARGET_H) + langhooks.h toplev.h flags.h $(GGC_H) $(TARGET_H) cgraph.h gt-cgraph.h \ + output.h intl.h +cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + langhooks.h tree-inline.h toplev.h flags.h $(GGC_H) $(TARGET_H) cgraph.h intl.h \ + function.h +coverage.o : coverage.c gcov-io.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(RTL_H) $(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \ + toplev.h $(GGC_H) $(TARGET_H) langhooks.h $(COVERAGE_H) libfuncs.h \ + gt-coverage.h $(HASHTAB_H) +cselib.o : cselib.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ + hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \ + output.h function.h cselib.h $(GGC_H) $(TM_P_H) gt-cselib.h $(PARAMS_H) cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ - hard-reg-set.h $(FLAGS_H) insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \ - output.h $(FUNCTION_H) $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) \ - except.h $(TARGET_H) $(PARAMS_H) rtlhooks-def.h tree-pass.h $(REAL_H) -web.o : web.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h toplev.h \ - $(DF_H) $(OBSTACK_H) $(TIMEVAR_H) tree-pass.h -see.o : see.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h toplev.h \ - $(DF_H) $(OBSTACK_H) $(TIMEVAR_H) tree-pass.h $(EXPR_H) -gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(REGS_H) hard-reg-set.h $(FLAGS_H) $(REAL_H) insn-config.h $(GGC_H) \ - $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h toplev.h \ - $(TM_P_H) $(PARAMS_H) except.h gt-gcse.h $(TREE_H) cselib.h $(TIMEVAR_H) \ - intl.h $(OBSTACK_H) tree-pass.h -resource.o : resource.c $(CONFIG_H) $(RTL_H) hard-reg-set.h $(SYSTEM_H) \ - coretypes.h $(TM_H) $(REGS_H) $(FLAGS_H) output.h $(RESOURCE_H) \ - $(FUNCTION_H) toplev.h $(INSN_ATTR_H) except.h $(PARAMS_H) $(TM_P_H) + hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \ + output.h function.h $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) \ + except.h $(TARGET_H) $(PARAMS_H) +web.o : web.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ + hard-reg-set.h flags.h $(BASIC_BLOCK_H) function.h output.h toplev.h df.h +gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ + hard-reg-set.h flags.h real.h insn-config.h $(GGC_H) $(RECOG_H) $(EXPR_H) \ + $(BASIC_BLOCK_H) function.h output.h toplev.h $(TM_P_H) $(PARAMS_H) \ + except.h gt-gcse.h $(TREE_H) cselib.h +sibcall.o : sibcall.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ + function.h hard-reg-set.h flags.h insn-config.h $(RECOG_H) $(BASIC_BLOCK_H) +resource.o : resource.c $(CONFIG_H) $(RTL_H) hard-reg-set.h $(SYSTEM_H) coretypes.h \ + $(TM_H) $(BASIC_BLOCK_H) $(REGS_H) flags.h output.h resource.h function.h toplev.h \ + $(INSN_ATTR_H) except.h $(PARAMS_H) $(TM_P_H) lcm.o : lcm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ - hard-reg-set.h $(FLAGS_H) insn-config.h $(INSN_ATTR_H) $(RECOG_H) \ - $(BASIC_BLOCK_H) $(TM_P_H) $(FUNCTION_H) output.h $(REAL_H) -mode-switching.o : mode-switching.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ - $(INSN_ATTR_H) $(RECOG_H) $(BASIC_BLOCK_H) $(TM_P_H) $(FUNCTION_H) \ - output.h tree-pass.h $(TIMEVAR_H) $(REAL_H) -tree-ssa-dce.o : tree-ssa-dce.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ - $(RTL_H) $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) \ - coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) $(BASIC_BLOCK_H) \ - $(GGC_H) hard-reg-set.h $(OBSTACK_H) $(TREE_GIMPLE_H) $(CFGLOOP_H) \ - $(SCEV_H) -tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_FLOW_H) $(CONFIG_H) \ - $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \ - $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ - $(TREE_DUMP_H) $(BASIC_BLOCK_H) tree-pass.h langhooks.h \ - tree-ssa-propagate.h $(FLAGS_H) $(TARGET_H) toplev.h -tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(RTL_H) \ - $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) $(TREE_INLINE_H) \ - $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_GIMPLE_H) \ - langhooks.h tree-pass.h $(FLAGS_H) $(EXPR_H) $(BASIC_BLOCK_H) \ - bitmap.h $(GGC_H) hard-reg-set.h $(OBSTACK_H) $(PARAMS_H) $(TARGET_H) -tree-complex.o : tree-complex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ - $(TM_H) $(RTL_H) $(REAL_H) $(FLAGS_H) $(TREE_FLOW_H) $(TREE_GIMPLE_H) \ - tree-iterator.h tree-pass.h tree-ssa-propagate.h $(DIAGNOSTIC_H) -tree-vect-generic.o : tree-vect-generic.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ - $(TM_H) $(TREE_FLOW_H) $(TREE_GIMPLE_H) tree-iterator.h tree-pass.h \ - $(FLAGS_H) $(OPTABS_H) $(RTL_H) $(MACHMODE_H) $(EXPR_H) \ - langhooks.h $(FLAGS_H) $(DIAGNOSTIC_H) gt-tree-vect-generic.h $(GGC_H) \ - coretypes.h insn-codes.h -df-core.o : df-core.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h \ - hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) bitmap.h sbitmap.h \ - $(TM_P_H) $(FLAGS_H) output.h tree-pass.h -df-problems.o : df-problems.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h \ - hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) bitmap.h sbitmap.h $(TM_P_H) \ - $(FLAGS_H) output.h vecprim.h -df-scan.o : df-scan.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h \ - hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) bitmap.h sbitmap.h $(TM_P_H) \ - $(FLAGS_H) $(TARGET_H) $(TARGET_DEF_H) $(TREE_H) output.h tree-pass.h -var-tracking.o : var-tracking.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(TREE_H) hard-reg-set.h insn-config.h reload.h $(FLAGS_H) \ - $(BASIC_BLOCK_H) output.h sbitmap.h alloc-pool.h $(FIBHEAP_H) $(HASHTAB_H) \ - $(REGS_H) $(EXPR_H) $(TIMEVAR_H) tree-pass.h + hard-reg-set.h flags.h real.h insn-config.h $(INSN_ATTR_H) $(RECOG_H) $(EXPR_H) \ + $(BASIC_BLOCK_H) $(TM_P_H) df.h function.h +df.o : df.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + insn-config.h $(RECOG_H) function.h $(REGS_H) alloc-pool.h hard-reg-set.h \ + $(BASIC_BLOCK_H) df.h $(FIBHEAP_H) conflict.o : conflict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(OBSTACK_H) \ $(HASHTAB_H) $(RTL_H) hard-reg-set.h $(BASIC_BLOCK_H) profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) $(FUNCTION_H) \ - toplev.h $(COVERAGE_H) $(TREE_FLOW_H) value-prof.h cfghooks.h \ - $(CFGLOOP_H) $(TIMEVAR_H) tree-pass.h -tree-profile.o : tree-profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) \ - $(FUNCTION_H) toplev.h $(COVERAGE_H) $(TREE_H) value-prof.h $(TREE_DUMP_H) \ - tree-pass.h $(TREE_FLOW_H) $(TIMEVAR_H) $(GGC_H) gt-tree-profile.h -value-prof.o : value-prof.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(BASIC_BLOCK_H) hard-reg-set.h value-prof.h $(EXPR_H) output.h $(FLAGS_H) \ - $(RECOG_H) insn-config.h $(OPTABS_H) $(REGS_H) $(GGC_H) $(DIAGNOSTIC_H) \ - $(TREE_H) $(COVERAGE_H) $(RTL_H) $(GCOV_IO_H) $(TREE_FLOW_H) \ - tree-flow-inline.h $(TIMEVAR_H) tree-pass.h -loop-doloop.o : loop-doloop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(FLAGS_H) $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TM_P_H) \ - toplev.h $(CFGLOOP_H) output.h $(PARAMS_H) $(TARGET_H) + $(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \ + toplev.h $(BASIC_BLOCK_H) $(COVERAGE_H) $(TREE_H) value-prof.h +value-prof.o : value-prof.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + $(BASIC_BLOCK_H) hard-reg-set.h value-prof.h $(EXPR_H) output.h flags.h \ + $(RECOG_H) insn-config.h $(OPTABS_H) $(REGS_H) +loop.o : loop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h $(LOOP_H) \ + insn-config.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) \ + real.h $(PREDICT_H) $(BASIC_BLOCK_H) function.h cfgloop.h \ + toplev.h varray.h except.h cselib.h $(OPTABS_H) $(TM_P_H) $(GGC_H) +doloop.o : doloop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ + $(LOOP_H) $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TM_P_H) toplev.h \ + cfgloop.h +unroll.o : unroll.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) insn-config.h \ + function.h $(INTEGRATE_H) $(REGS_H) $(RECOG_H) flags.h $(EXPR_H) $(LOOP_H) toplev.h \ + hard-reg-set.h varray.h $(BASIC_BLOCK_H) $(TM_P_H) $(PREDICT_H) $(PARAMS_H) \ + cfgloop.h alloc-pool.o : alloc-pool.c $(CONFIG_H) $(SYSTEM_H) alloc-pool.h $(HASHTAB_H) -flow.o : flow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) \ - hard-reg-set.h output.h toplev.h $(RECOG_H) $(FUNCTION_H) except.h \ - $(EXPR_H) $(TM_P_H) $(OBSTACK_H) $(SPLAY_TREE_H) $(TIMEVAR_H) tree-pass.h -cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) \ - $(REGS_H) hard-reg-set.h output.h toplev.h $(FUNCTION_H) except.h $(GGC_H) \ - $(TM_P_H) $(TIMEVAR_H) $(OBSTACK_H) $(TREE_H) alloc-pool.h $(HASHTAB_H) -cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TIMEVAR_H) toplev.h -cfgexpand.o : cfgexpand.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ - $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) \ - coretypes.h $(TREE_DUMP_H) except.h langhooks.h tree-pass.h $(RTL_H) \ - $(DIAGNOSTIC_H) toplev.h $(BASIC_BLOCK_H) $(FLAGS_H) debug.h $(PARAMS_H) -cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h \ - output.h toplev.h $(FUNCTION_H) except.h $(TM_P_H) insn-config.h $(EXPR_H) \ - $(CFGLAYOUT_H) $(CFGLOOP_H) $(OBSTACK_H) $(TARGET_H) $(TREE_H) \ - tree-pass.h +flow.o : flow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \ + $(RECOG_H) function.h except.h $(EXPR_H) $(GGC_H) $(TM_P_H) +cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h insn-config.h \ + $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \ + function.h except.h $(GGC_H) $(TM_P_H) alloc-pool.h +cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + $(BASIC_BLOCK_H) cfglayout.h +cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ + insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \ + function.h except.h $(GGC_H) $(TM_P_H) insn-config.h $(EXPR_H) cfganal.o : cfganal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(BASIC_BLOCK_H) hard-reg-set.h insn-config.h $(RECOG_H) $(TM_P_H) \ - $(TIMEVAR_H) $(OBSTACK_H) toplev.h -cfgbuild.o : cfgbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FLAGS_H) $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \ - $(FUNCTION_H) except.h $(TIMEVAR_H) $(TREE_H) + $(BASIC_BLOCK_H) hard-reg-set.h insn-config.h $(RECOG_H) $(GGC_H) $(TM_P_H) +cfgbuild.o : cfgbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ + insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \ + function.h except.h $(GGC_H) cfgcleanup.o : cfgcleanup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(TIMEVAR_H) hard-reg-set.h output.h $(FLAGS_H) $(RECOG_H) \ - toplev.h insn-config.h cselib.h $(TARGET_H) $(TM_P_H) $(PARAMS_H) \ - $(REGS_H) $(EMIT_RTL_H) $(CFGLAYOUT_H) tree-pass.h $(CFGLOOP_H) $(EXPR_H) + $(RTL_H) $(TIMEVAR_H) $(BASIC_BLOCK_H) hard-reg-set.h output.h flags.h \ + $(RECOG_H) toplev.h $(GGC_H) insn-config.h cselib.h $(TARGET_H) $(TM_P_H) \ + $(PARAMS_H) cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) coretypes.h $(TM_H) \ - $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(FLAGS_H) $(FUNCTION_H) \ - $(OBSTACK_H) toplev.h $(TREE_FLOW_H) $(TREE_H) + $(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h flags.h cfgloopanal.o : cfgloopanal.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ - $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) \ - $(OBSTACK_H) output.h -struct-equiv.o : struct-equiv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) hard-reg-set.h output.h $(FLAGS_H) $(RECOG_H) \ - insn-config.h $(TARGET_H) $(TM_P_H) $(PARAMS_H) \ - $(REGS_H) $(EMIT_RTL_H) -loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \ - hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) \ - output.h intl.h $(DF_H) $(HASHTAB_H) -loop-invariant.o : loop-invariant.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ - $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h \ - $(TM_H) $(TM_P_H) $(FUNCTION_H) $(FLAGS_H) $(DF_H) $(OBSTACK_H) output.h \ - $(HASHTAB_H) except.h + $(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h $(EXPR_H) coretypes.h $(TM_H) cfgloopmanip.o : cfgloopmanip.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ - $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) output.h \ - coretypes.h $(TM_H) cfghooks.h $(OBSTACK_H) + $(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h cfglayout.h output.h coretypes.h $(TM_H) loop-init.o : loop-init.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ - $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) \ - coretypes.h $(TM_H) $(OBSTACK_H) tree-pass.h $(TIMEVAR_H) $(FLAGS_H) + $(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h cfglayout.h \ + coretypes.h $(TM_H) loop-unswitch.o : loop-unswitch.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_H) \ - $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) $(PARAMS_H) \ - output.h $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) + $(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h cfglayout.h $(PARAMS_H) \ + output.h $(EXPR_H) coretypes.h $(TM_H) loop-unroll.o: loop-unroll.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_H) \ - $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) $(PARAMS_H) \ - output.h $(EXPR_H) coretypes.h $(TM_H) $(HASHTAB_H) $(RECOG_H) \ - $(OBSTACK_H) + $(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h cfglayout.h $(PARAMS_H) \ + output.h $(EXPR_H) coretypes.h $(TM_H) dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - hard-reg-set.h $(BASIC_BLOCK_H) et-forest.h $(OBSTACK_H) toplev.h $(TIMEVAR_H) -et-forest.o : et-forest.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - et-forest.h alloc-pool.h $(BASIC_BLOCK_H) -combine.o : combine.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FLAGS_H) $(FUNCTION_H) insn-config.h $(INSN_ATTR_H) $(REGS_H) $(EXPR_H) \ - rtlhooks-def.h $(BASIC_BLOCK_H) $(RECOG_H) $(REAL_H) hard-reg-set.h \ - toplev.h $(TM_P_H) $(TREE_H) $(TARGET_H) output.h $(PARAMS_H) $(OPTABS_H) \ - insn-codes.h $(TIMEVAR_H) tree-pass.h + hard-reg-set.h $(BASIC_BLOCK_H) et-forest.h +et-forest.o : et-forest.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) et-forest.h alloc-pool.h +combine.o : combine.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ + function.h insn-config.h $(INSN_ATTR_H) $(REGS_H) $(EXPR_H) \ + $(BASIC_BLOCK_H) $(RECOG_H) real.h hard-reg-set.h toplev.h $(TM_P_H) \ + $(TREE_H) $(TARGET_H) $(PARAMS_H) regclass.o : regclass.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(REGS_H) insn-config.h \ - $(RECOG_H) reload.h $(REAL_H) toplev.h $(FUNCTION_H) output.h $(GGC_H) \ - $(TM_P_H) $(EXPR_H) $(TIMEVAR_H) gt-regclass.h $(HASHTAB_H) \ - $(TARGET_H) -local-alloc.o : local-alloc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(FLAGS_H) $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) \ - output.h $(FUNCTION_H) $(INSN_ATTR_H) toplev.h except.h reload.h $(TM_P_H) \ - $(GGC_H) $(INTEGRATE_H) $(TIMEVAR_H) tree-pass.h -bitmap.o : bitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FLAGS_H) $(GGC_H) gt-bitmap.h bitmap.h $(OBSTACK_H) -global.o : global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FLAGS_H) reload.h $(FUNCTION_H) $(RECOG_H) $(REGS_H) hard-reg-set.h \ - insn-config.h output.h toplev.h $(TM_P_H) $(MACHMODE_H) tree-pass.h \ - $(TIMEVAR_H) vecprim.h -varray.o : varray.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GGC_H) \ - $(HASHTAB_H) $(BCONFIG_H) $(VARRAY_H) toplev.h -vec.o : vec.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) coretypes.h vec.h $(GGC_H) \ - toplev.h -reload.o : reload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FLAGS_H) output.h $(EXPR_H) $(OPTABS_H) reload.h $(RECOG_H) \ - hard-reg-set.h insn-config.h $(REGS_H) $(FUNCTION_H) toplev.h \ - addresses.h $(TM_P_H) $(PARAMS_H) $(TARGET_H) $(REAL_H) -reload1.o : reload1.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + hard-reg-set.h flags.h $(BASIC_BLOCK_H) $(REGS_H) insn-config.h $(RECOG_H) reload.h \ + real.h toplev.h function.h output.h $(GGC_H) $(TM_P_H) $(EXPR_H) $(TIMEVAR_H) +local-alloc.o : local-alloc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + flags.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) \ + output.h function.h $(INSN_ATTR_H) toplev.h except.h $(TM_P_H) +bitmap.o : bitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) $(RTL_H) flags.h \ + $(BASIC_BLOCK_H) $(REGS_H) $(GGC_H) + $(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) +global.o : global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ + reload.h function.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h insn-config.h output.h \ + toplev.h $(TM_P_H) +varray.o : varray.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) varray.h $(GGC_H) errors.h +ra.o : ra.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TM_P_H) insn-config.h \ + $(RECOG_H) $(INTEGRATE_H) function.h $(REGS_H) $(OBSTACK_H) hard-reg-set.h \ + $(BASIC_BLOCK_H) df.h $(EXPR_H) output.h toplev.h flags.h reload.h ra.h +ra-build.o : ra-build.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TM_P_H) \ + insn-config.h $(RECOG_H) function.h $(REGS_H) hard-reg-set.h \ + $(BASIC_BLOCK_H) df.h output.h $(GGC_H) ra.h gt-ra-build.h reload.h +ra-colorize.o : ra-colorize.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + $(TM_P_H) function.h $(REGS_H) hard-reg-set.h $(BASIC_BLOCK_H) df.h output.h ra.h +ra-debug.o : ra-debug.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + insn-config.h $(RECOG_H) function.h hard-reg-set.h $(BASIC_BLOCK_H) df.h output.h \ + ra.h $(TM_P_H) +ra-rewrite.o : ra-rewrite.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + $(TM_P_H) function.h $(REGS_H) hard-reg-set.h $(BASIC_BLOCK_H) df.h $(EXPR_H) \ + output.h except.h ra.h reload.h insn-config.h +reload.o : reload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h output.h \ + $(EXPR_H) $(OPTABS_H) reload.h $(RECOG_H) hard-reg-set.h insn-config.h \ + $(REGS_H) function.h real.h toplev.h $(TM_P_H) $(PARAMS_H) +reload1.o : reload1.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) real.h flags.h \ + $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) hard-reg-set.h insn-config.h \ + $(BASIC_BLOCK_H) $(RECOG_H) output.h function.h toplev.h $(TM_P_H) \ + except.h $(TREE_H) +postreload.o : postreload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) real.h flags.h \ $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) hard-reg-set.h insn-config.h \ - $(BASIC_BLOCK_H) $(RECOG_H) output.h $(FUNCTION_H) toplev.h $(TM_P_H) \ - addresses.h except.h $(TREE_H) $(REAL_H) $(FLAGS_H) $(MACHMODE_H) \ - $(OBSTACK_H) $(TARGET_H) -rtlhooks.o : rtlhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - rtlhooks-def.h $(EXPR_H) $(RECOG_H) -postreload.o : postreload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(REAL_H) $(FLAGS_H) $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) \ - hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) $(RECOG_H) output.h \ - $(FUNCTION_H) toplev.h cselib.h $(TM_P_H) except.h $(TREE_H) $(MACHMODE_H) \ - $(OBSTACK_H) $(TIMEVAR_H) tree-pass.h -postreload-gcse.o : postreload-gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ - $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h toplev.h \ - $(TM_P_H) except.h $(TREE_H) $(TARGET_H) $(HASHTAB_H) intl.h $(OBSTACK_H) \ - $(PARAMS_H) $(TIMEVAR_H) tree-pass.h $(REAL_H) + $(BASIC_BLOCK_H) $(RECOG_H) output.h function.h toplev.h cselib.h $(TM_P_H) \ + except.h $(TREE_H) caller-save.o : caller-save.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FLAGS_H) $(REGS_H) hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) $(FUNCTION_H) \ - addresses.h $(RECOG_H) reload.h $(EXPR_H) toplev.h $(TM_P_H) -bt-load.o : bt-load.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) except.h \ - $(RTL_H) hard-reg-set.h $(REGS_H) $(TM_P_H) $(FIBHEAP_H) output.h $(EXPR_H) \ - $(TARGET_H) $(FLAGS_H) $(INSN_ATTR_H) $(FUNCTION_H) tree-pass.h toplev.h -reorg.o : reorg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - conditions.h hard-reg-set.h $(BASIC_BLOCK_H) $(REGS_H) insn-config.h \ - $(INSN_ATTR_H) except.h $(RECOG_H) $(FUNCTION_H) $(FLAGS_H) output.h \ - $(EXPR_H) toplev.h $(PARAMS_H) $(TM_P_H) $(OBSTACK_H) $(RESOURCE_H) \ - $(TIMEVAR_H) $(TARGET_H) tree-pass.h -alias.o : alias.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FLAGS_H) hard-reg-set.h $(BASIC_BLOCK_H) $(REGS_H) toplev.h output.h \ - $(ALIAS_H) $(EMIT_RTL_H) $(GGC_H) $(FUNCTION_H) cselib.h $(TREE_H) $(TM_P_H) \ - langhooks.h $(TARGET_H) gt-alias.h $(TIMEVAR_H) $(CGRAPH_H) \ - $(SPLAY_TREE_H) $(VARRAY_H) $(IPA_TYPE_ESCAPE_H) tree-pass.h -regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - insn-config.h $(TIMEVAR_H) tree-pass.h \ - $(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) $(FUNCTION_H) \ + flags.h $(REGS_H) hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) function.h \ + $(RECOG_H) reload.h $(EXPR_H) toplev.h $(TM_P_H) +bt-load.o : bt-load.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(BASIC_BLOCK_H) $(RTL_H) hard-reg-set.h $(REGS_H) $(OBSTACK_H) $(TM_P_H) \ + $(FIBHEAP_H) output.h $(TARGET_H) $(EXPR_H) flags.h $(INSN_ATTR_H) +reorg.o : reorg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) conditions.h \ + hard-reg-set.h $(BASIC_BLOCK_H) $(REGS_H) insn-config.h $(INSN_ATTR_H) except.h \ + $(RECOG_H) function.h flags.h output.h $(EXPR_H) toplev.h $(PARAMS_H) $(TM_P_H) +alias.o : alias.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ + hard-reg-set.h $(BASIC_BLOCK_H) $(REGS_H) toplev.h output.h $(EXPR_H) \ + $(GGC_H) function.h cselib.h $(TREE_H) $(TM_P_H) langhooks.h $(TARGET_H) \ + gt-alias.h $(TIMEVAR_H) cgraph.h +regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) insn-config.h \ + $(RECOG_H) output.h $(REGS_H) hard-reg-set.h flags.h function.h \ $(EXPR_H) $(BASIC_BLOCK_H) toplev.h $(TM_P_H) except.h reload.h -ddg.o : ddg.c $(DDG_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) \ - toplev.h $(RTL_H) $(TM_P_H) $(REGS_H) $(FUNCTION_H) \ - $(FLAGS_H) insn-config.h $(INSN_ATTR_H) except.h $(RECOG_H) \ - $(SCHED_INT_H) $(CFGLAYOUT_H) $(CFGLOOP_H) $(EXPR_H) bitmap.h $(DF_H) \ - hard-reg-set.h sbitmap.h $(TM_H) -modulo-sched.o : modulo-sched.c $(DDG_H) $(CONFIG_H) $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TARGET_H) toplev.h $(RTL_H) $(TM_P_H) $(REGS_H) $(FUNCTION_H) \ - $(FLAGS_H) insn-config.h $(INSN_ATTR_H) except.h $(RECOG_H) \ - $(SCHED_INT_H) $(CFGLAYOUT_H) $(CFGLOOP_H) $(EXPR_H) $(PARAMS_H) \ - cfghooks.h $(DF_H) $(GCOV_IO_H) hard-reg-set.h $(TM_H) $(TIMEVAR_H) \ - tree-pass.h -haifa-sched.o : haifa-sched.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ - $(FUNCTION_H) $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(TM_P_H) \ - $(TARGET_H) output.h $(PARAMS_H) -sched-deps.o : sched-deps.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ - $(FUNCTION_H) $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h cselib.h \ - $(PARAMS_H) $(TM_P_H) $(DF_H) -sched-rgn.o : sched-rgn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ - $(FUNCTION_H) $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(PARAMS_H) \ - $(TM_P_H) $(TARGET_H) $(CFGLAYOUT_H) $(TIMEVAR_H) tree-pass.h -sched-ebb.o : sched-ebb.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ - $(FUNCTION_H) $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(TM_P_H) \ - $(PARAMS_H) $(CFGLAYOUT_H) $(TARGET_H) output.h -sched-vis.o : sched-vis.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(SCHED_INT_H) hard-reg-set.h $(BASIC_BLOCK_H) $(OBSTACK_H) \ - $(TM_P_H) $(REAL_H) toplev.h tree-pass.h -final.o : final.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) intl.h $(REGS_H) $(RECOG_H) conditions.h \ - insn-config.h $(INSN_ATTR_H) $(FUNCTION_H) output.h hard-reg-set.h \ - except.h debug.h xcoffout.h toplev.h reload.h dwarf2out.h tree-pass.h \ - $(BASIC_BLOCK_H) $(TM_P_H) $(TARGET_H) $(EXPR_H) $(CFGLAYOUT_H) dbxout.h \ - $(TIMEVAR_H) $(CGRAPH_H) $(COVERAGE_H) $(REAL_H) -recog.o : recog.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(FUNCTION_H) $(BASIC_BLOCK_H) $(REGS_H) $(RECOG_H) $(EXPR_H) \ - $(FLAGS_H) insn-config.h $(INSN_ATTR_H) toplev.h output.h reload.h \ - addresses.h $(TM_P_H) $(TIMEVAR_H) tree-pass.h hard-reg-set.h $(REAL_H) -reg-stack.o : reg-stack.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(TREE_H) $(RECOG_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \ - insn-config.h toplev.h reload.h $(FUNCTION_H) $(TM_P_H) $(GGC_H) \ - $(BASIC_BLOCK_H) output.h $(VARRAY_H) $(TIMEVAR_H) tree-pass.h \ - $(TARGET_H) vecprim.h +haifa-sched.o : haifa-sched.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + sched-int.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \ + $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(TM_P_H) $(TARGET_H) +sched-deps.o : sched-deps.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + sched-int.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \ + $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h cselib.h $(PARAMS_H) $(TM_P_H) +sched-rgn.o : sched-rgn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + sched-int.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \ + $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(TM_P_H) $(TARGET_H) +sched-ebb.o : sched-ebb.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + sched-int.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \ + $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(TM_P_H) $(PARAMS_H) +sched-vis.o : sched-vis.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + sched-int.h hard-reg-set.h $(BASIC_BLOCK_H) $(INSN_ATTR_H) $(REGS_H) $(TM_P_H) \ + $(TARGET_H) real.h +final.o : final.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h intl.h $(REGS_H) $(RECOG_H) conditions.h insn-config.h $(INSN_ATTR_H) \ + function.h real.h output.h hard-reg-set.h except.h debug.h xcoffout.h \ + toplev.h reload.h dwarf2out.h $(BASIC_BLOCK_H) $(TM_P_H) $(TARGET_H) \ + $(EXPR_H) +recog.o : recog.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) function.h \ + $(BASIC_BLOCK_H) $(REGS_H) $(RECOG_H) $(EXPR_H) hard-reg-set.h flags.h insn-config.h \ + $(INSN_ATTR_H) real.h toplev.h output.h reload.h $(TM_P_H) +reg-stack.o : reg-stack.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + $(RECOG_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h toplev.h reload.h \ + varray.h function.h $(TM_P_H) $(GGC_H) gt-reg-stack.h sreal.o: sreal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) sreal.h -predict.o: predict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) \ - hard-reg-set.h output.h toplev.h $(RECOG_H) $(FUNCTION_H) except.h \ - $(TM_P_H) $(PREDICT_H) sreal.h $(PARAMS_H) $(TARGET_H) $(CFGLOOP_H) \ - $(COVERAGE_H) $(SCEV_H) $(GGC_H) predict.def $(TIMEVAR_H) $(TREE_DUMP_H) \ - $(TREE_FLOW_H) tree-pass.h $(EXPR_H) -lists.o: lists.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h \ - $(RTL_H) $(GGC_H) gt-lists.h +predict.o: predict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \ + $(RECOG_H) function.h except.h $(EXPR_H) $(TM_P_H) $(PREDICT_H) sreal.h \ + $(PARAMS_H) $(TARGET_H) cfgloop.h $(COVERAGE_H) +lists.o: lists.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h $(RTL_H) $(GGC_H) bb-reorder.o : bb-reorder.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(FLAGS_H) $(TIMEVAR_H) output.h $(CFGLAYOUT_H) $(FIBHEAP_H) \ - $(TARGET_H) $(FUNCTION_H) $(TM_P_H) $(OBSTACK_H) $(EXPR_H) $(REGS_H) \ - $(PARAMS_H) toplev.h tree-pass.h -tracer.o : tracer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(BASIC_BLOCK_H) hard-reg-set.h output.h $(CFGLAYOUT_H) \ - $(FLAGS_H) $(TIMEVAR_H) $(PARAMS_H) $(COVERAGE_H) $(FIBHEAP_H) \ - tree-pass.h + $(RTL_H) $(BASIC_BLOCK_H) flags.h timevar.h output.h cfglayout.h $(FIBHEAP_H) \ + $(TARGET_H) +tracer.o : tracer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + $(BASIC_BLOCK_H) hard-reg-set.h output.h cfglayout.h flags.h timevar.h \ + $(PARAMS_H) $(COVERAGE_H) cfglayout.o : cfglayout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(TREE_H) insn-config.h $(BASIC_BLOCK_H) hard-reg-set.h output.h \ - $(FUNCTION_H) $(CFGLAYOUT_H) $(CFGLOOP_H) $(TARGET_H) gt-cfglayout.h \ - $(GGC_H) alloc-pool.h $(FLAGS_H) $(OBSTACK_H) tree-pass.h vecprim.h -timevar.o : timevar.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TIMEVAR_H) $(FLAGS_H) intl.h toplev.h $(RTL_H) timevar.def -regrename.o : regrename.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h \ - output.h $(RECOG_H) $(FUNCTION_H) $(OBSTACK_H) $(FLAGS_H) $(TM_P_H) \ - addresses.h reload.h toplev.h $(TIMEVAR_H) tree-pass.h + function.h cfglayout.h cfgloop.h $(TARGET_H) gt-cfglayout.h $(GGC_H) +timevar.o : timevar.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TIMEVAR_H) flags.h \ + intl.h toplev.h +regrename.o : regrename.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h $(RECOG_H) function.h \ + resource.h $(OBSTACK_H) flags.h $(TM_P_H) ifcvt.o : ifcvt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(REGS_H) toplev.h $(FLAGS_H) insn-config.h $(FUNCTION_H) $(RECOG_H) \ - $(TARGET_H) $(BASIC_BLOCK_H) $(EXPR_H) output.h except.h $(TM_P_H) \ - $(REAL_H) $(OPTABS_H) $(CFGLOOP_H) hard-reg-set.h $(TIMEVAR_H) tree-pass.h -lambda-mat.o : lambda-mat.c $(LAMBDA_H) $(GGC_H) $(SYSTEM_H) $(CONFIG_H) \ - $(TM_H) coretypes.h $(TREE_H) -lambda-trans.o: lambda-trans.c $(LAMBDA_H) $(GGC_H) $(SYSTEM_H) $(CONFIG_H) \ - $(TM_H) coretypes.h $(TARGET_H) $(TREE_H) -lambda-code.o: lambda-code.c $(LAMBDA_H) $(GGC_H) $(SYSTEM_H) $(CONFIG_H) \ - $(TM_H) $(OPTABS_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) \ - $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \ - $(TREE_DATA_REF_H) $(SCEV_H) $(EXPR_H) coretypes.h $(TARGET_H) \ - tree-chrec.h tree-pass.h vec.h vecprim.h + $(REGS_H) toplev.h flags.h insn-config.h function.h $(RECOG_H) $(TARGET_H) \ + $(BASIC_BLOCK_H) $(EXPR_H) output.h except.h $(TM_P_H) real.h $(OPTABS_H) \ + cfgloop.h params.o : params.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(PARAMS_H) toplev.h -pointer-set.o: pointer-set.c pointer-set.h $(CONFIG_H) $(SYSTEM_H) hooks.o: hooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(HOOKS_H) -pretty-print.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h intl.h $(PRETTY_PRINT_H) \ - $(TREE_H) -errors.o : errors.c $(CONFIG_H) $(SYSTEM_H) errors.h $(BCONFIG_H) +pretty-print.o: $(CONFIG_H) $(SYSTEM_H) pretty-print.c $(PRETTY_PRINT_H) -$(out_object_file): $(out_file) $(CONFIG_H) coretypes.h $(TM_H) $(TREE_H) \ - $(RTL_H) $(REGS_H) hard-reg-set.h insn-config.h conditions.h \ +$(out_object_file): $(out_file) $(CONFIG_H) coretypes.h $(TM_H) $(TREE_H) $(GGC_H) \ + $(RTL_H) $(REGS_H) hard-reg-set.h real.h insn-config.h conditions.h \ output.h $(INSN_ATTR_H) $(SYSTEM_H) toplev.h $(TARGET_H) libfuncs.h \ - $(TARGET_DEF_H) $(FUNCTION_H) $(SCHED_INT_H) $(TM_P_H) $(EXPR_H) \ - langhooks.h $(GGC_H) $(OPTABS_H) $(REAL_H) tm-constrs.h - $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(TARGET_DEF_H) function.h sched-int.h $(TM_P_H) $(EXPR_H) $(OPTABS_H) \ + langhooks.h + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(out_file) $(OUTPUT_OPTION) # Build auxiliary files that support ecoff format. mips-tfile: mips-tfile.o version.o $(LIBDEPS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ mips-tfile.o version.o $(LIBS) -mips-tfile.o : mips-tfile.c $(CONFIG_H) $(RTL_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) version.h $(srcdir)/../include/getopt.h gstab.h intl.h +mips-tfile.o : mips-tfile.c $(CONFIG_H) $(RTL_H) $(SYSTEM_H) coretypes.h $(TM_H) version.h mips-tdump: mips-tdump.o version.o $(LIBDEPS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ mips-tdump.o version.o $(LIBS) -mips-tdump.o : mips-tdump.c $(CONFIG_H) $(RTL_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) version.h $(srcdir)/../include/getopt.h stab.def +mips-tdump.o : mips-tdump.c $(CONFIG_H) $(RTL_H) $(SYSTEM_H) coretypes.h $(TM_H) version.h # FIXME: writing proper dependencies for this is a *LOT* of work. libbackend.o : $(OBJS-common:.o=.c) $(out_file) \ insn-config.h insn-flags.h insn-codes.h insn-constants.h \ - insn-attr.h $(DATESTAMP) $(BASEVER) $(DEVPHASE) - $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + insn-attr.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ -DTARGET_NAME=\"$(target_noncanonical)\" \ -DLOCALEDIR=\"$(localedir)\" \ - -c $(filter %.c,$^) -o $@ \ - -DBASEVER=$(BASEVER_s) -DDATESTAMP=$(DATESTAMP_s) \ - -DDEVPHASE=$(DEVPHASE_s) -combine + -c $(filter %.c,$^) -o $@ # # Generate header and source files from the machine description, @@ -2674,204 +1895,205 @@ libbackend.o : $(OBJS-common:.o=.c) $(out_file) \ .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \ insn-emit.c insn-recog.c insn-extract.c insn-output.c insn-peep.c \ - insn-attr.h insn-attrtab.c insn-preds.c - -# Dependencies for the md file. The first time through, we just assume -# the md file itself and the generated dependency file (in order to get -# it built). The second time through we have the dependency file. --include mddeps.mk -MD_DEPS = s-mddeps $(md_file) $(MD_INCLUDES) - -s-mddeps: $(md_file) $(MD_INCLUDES) build/genmddeps$(build_exeext) - $(RUN_GEN) build/genmddeps$(build_exeext) $(md_file) > tmp-mddeps - $(SHELL) $(srcdir)/../move-if-change tmp-mddeps mddeps.mk - $(STAMP) s-mddeps - -# Header dependencies for generated source files. -genrtl.o : genrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H)\ - $(GGC_H) -insn-attrtab.o : insn-attrtab.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) $(REGS_H) $(REAL_H) output.h $(INSN_ATTR_H) \ - insn-config.h toplev.h $(RECOG_H) $(TM_P_H) $(FLAGS_H) -insn-automata.o : insn-automata.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) $(REGS_H) $(REAL_H) output.h $(INSN_ATTR_H) \ - insn-config.h toplev.h $(RECOG_H) $(TM_P_H) $(FLAGS_H) -insn-emit.o : insn-emit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(EXPR_H) $(REAL_H) output.h insn-config.h $(OPTABS_H) \ - reload.h $(RECOG_H) toplev.h $(FUNCTION_H) $(FLAGS_H) hard-reg-set.h \ - $(RESOURCE_H) $(TM_P_H) $(BASIC_BLOCK_H) tm-constrs.h -insn-extract.o : insn-extract.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) toplev.h insn-config.h $(RECOG_H) -insn-modes.o : insn-modes.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(MACHMODE_H) $(REAL_H) -insn-opinit.o : insn-opinit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) insn-config.h $(FLAGS_H) $(RECOG_H) $(EXPR_H) \ - $(OPTABS_H) reload.h -insn-output.o : insn-output.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) $(GGC_H) $(REGS_H) $(REAL_H) conditions.h \ - hard-reg-set.h insn-config.h $(INSN_ATTR_H) $(EXPR_H) output.h \ - $(RECOG_H) $(FUNCTION_H) toplev.h $(FLAGS_H) insn-codes.h $(TM_P_H) \ - $(TARGET_H) tm-constrs.h -insn-peep.o : insn-peep.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(REGS_H) output.h insn-config.h $(RECOG_H) except.h \ - $(FUNCTION_H) $(TM_P_H) $(REAL_H) tm-constrs.h -insn-preds.o : insn-preds.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) $(TREE_H) insn-config.h $(RECOG_H) output.h \ - $(FLAGS_H) $(FUNCTION_H) hard-reg-set.h $(RESOURCE_H) $(TM_P_H) \ - toplev.h reload.h $(REGS_H) $(REAL_H) tm-constrs.h -insn-recog.o : insn-recog.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) insn-config.h $(RECOG_H) output.h $(FLAGS_H) \ - $(FUNCTION_H) hard-reg-set.h $(RESOURCE_H) $(TM_P_H) toplev.h \ - reload.h $(REAL_H) tm-constrs.h - -# For each of the files generated by running a generator program over -# the machine description, the following pair of static pattern rules -# runs the generator program only if the machine description has changed, -# but touches the target file only when its contents actually change. -# The "; @true" construct forces Make to recheck the timestamp on the -# target file. - -simple_generated_h = insn-attr.h insn-codes.h insn-config.h insn-flags.h - -simple_generated_c = insn-attrtab.c insn-automata.c insn-emit.c \ - insn-extract.c insn-opinit.c insn-output.c \ - insn-peep.c insn-recog.c - -$(simple_generated_h): insn-%.h: s-%; @true - -$(simple_generated_h:insn-%.h=s-%): s-%: build/gen%$(build_exeext) \ - $(MD_DEPS) insn-conditions.md - $(RUN_GEN) build/gen$*$(build_exeext) $(md_file) \ - insn-conditions.md > tmp-$*.h - $(SHELL) $(srcdir)/../move-if-change tmp-$*.h insn-$*.h - $(STAMP) s-$* - -$(simple_generated_c): insn-%.c: s-%; @true -$(simple_generated_c:insn-%.c=s-%): s-%: build/gen%$(build_exeext) \ - $(MD_DEPS) insn-conditions.md - $(RUN_GEN) build/gen$*$(build_exeext) $(md_file) \ - insn-conditions.md > tmp-$*.c - $(SHELL) $(srcdir)/../move-if-change tmp-$*.c insn-$*.c - $(STAMP) s-$* - -# genconstants needs to run before insn-conditions.md is available -# (because the constants may be used in the conditions). -insn-constants.h: s-constants; @true -s-constants: build/genconstants$(build_exeext) $(MD_DEPS) - $(RUN_GEN) build/genconstants$(build_exeext) $(md_file) \ - > tmp-constants.h - $(SHELL) $(srcdir)/../move-if-change tmp-constants.h insn-constants.h - $(STAMP) s-constants - -# gencheck doesn't read the machine description, and the file produced -# doesn't use the insn-* convention. -tree-check.h: s-check ; @true -s-check : build/gencheck$(build_exeext) - $(RUN_GEN) build/gencheck$(build_exeext) > tmp-check.h - $(SHELL) $(srcdir)/../move-if-change tmp-check.h tree-check.h - $(STAMP) s-check - -# gencondmd doesn't use the standard naming convention. -build/gencondmd.c: s-conditions; @true -s-conditions: $(MD_DEPS) build/genconditions$(build_exeext) - $(RUN_GEN) build/genconditions$(build_exeext) $(md_file) > tmp-condmd.c - $(SHELL) $(srcdir)/../move-if-change tmp-condmd.c build/gencondmd.c + insn-attr.h insn-attrtab.c + +# The following pair of rules has this effect: +# genconfig is run only if the md has changed since genconfig was last run; +# but the file insn-config.h is touched only when its contents actually change. + +# Each of the other insn-* files is handled by a similar pair of rules. + +# This causes an anomaly in the results of make -n +# because insn-* is older than s-* +# and thus make -n thinks that insn-* will be updated +# and force recompilation of things that depend on it. +# We use move-if-change precisely to avoid such recompilation. +# But there is no way to teach make -n that it will be avoided. + +# Each of the insn-*.[ch] rules has a semicolon at the end, +# for otherwise the system Make on SunOS 4.1 never tries +# to recompile insn-*.o. To avoid problems and extra noise from +# versions of make which don't like empty commands (nothing after the +# trailing `;'), we call true for each. + +insn-config.h: s-config ; @true +s-config : $(md_file) genconfig$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genconfig$(build_exeext) $(md_file) > tmp-config.h + $(SHELL) $(srcdir)/move-if-change tmp-config.h insn-config.h + $(STAMP) s-config + +insn-conditions.c: s-conditions ; @true +s-conditions : $(md_file) genconditions$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genconditions$(build_exeext) $(md_file) > tmp-conditions.c + $(SHELL) $(srcdir)/move-if-change tmp-conditions.c insn-conditions.c $(STAMP) s-conditions -insn-conditions.md: s-condmd; @true -s-condmd: build/gencondmd$(build_exeext) - $(RUN_GEN) build/gencondmd$(build_exeext) > tmp-cond.md - $(SHELL) $(srcdir)/../move-if-change tmp-cond.md insn-conditions.md - $(STAMP) s-condmd - - -# These files are generated by running the same generator more than -# once with different options, so they have custom rules. The -# stampfile idiom is the same. -genrtl.c: s-genrtl; @true -genrtl.h: s-genrtl-h; @true +insn-conditions.o : insn-conditions.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(GTM_H) $(RTL_H) $(TM_P_H) $(REGS_H) function.h $(RECOG_H) real.h output.h \ + flags.h hard-reg-set.h resource.h toplev.h reload.h gensupport.h \ + insn-constants.h + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) insn-conditions.c + +dummy-conditions.o : dummy-conditions.c $(BCONFIG_H) $(SYSTEM_H) \ + coretypes.h $(GTM_H) gensupport.h + +insn-flags.h: s-flags ; @true +s-flags : $(md_file) genflags$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genflags$(build_exeext) $(md_file) > tmp-flags.h + $(SHELL) $(srcdir)/move-if-change tmp-flags.h insn-flags.h + $(STAMP) s-flags + +insn-codes.h: s-codes ; @true +s-codes : $(md_file) gencodes$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./gencodes$(build_exeext) $(md_file) > tmp-codes.h + $(SHELL) $(srcdir)/move-if-change tmp-codes.h insn-codes.h + $(STAMP) s-codes + +insn-constants.h: s-constants ; @true +s-constants : $(md_file) genconstants$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genconstants$(build_exeext) $(md_file) > tmp-constants.h + $(SHELL) $(srcdir)/move-if-change tmp-constants.h insn-constants.h + $(STAMP) s-constants -s-genrtl: build/gengenrtl$(build_exeext) - $(RUN_GEN) build/gengenrtl$(build_exeext) > tmp-genrtl.c - $(SHELL) $(srcdir)/../move-if-change tmp-genrtl.c genrtl.c +insn-emit.o : insn-emit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(EXPR_H) real.h output.h insn-config.h $(OPTABS_H) reload.h \ + $(RECOG_H) toplev.h function.h flags.h hard-reg-set.h resource.h $(TM_P_H) + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-emit.c \ + $(OUTPUT_OPTION) + +insn-emit.c: s-emit ; @true +s-emit : $(md_file) genemit$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genemit$(build_exeext) $(md_file) > tmp-emit.c + $(SHELL) $(srcdir)/move-if-change tmp-emit.c insn-emit.c + $(STAMP) s-emit + +insn-recog.o : insn-recog.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) insn-config.h $(RECOG_H) real.h output.h flags.h function.h \ + hard-reg-set.h resource.h $(TM_P_H) toplev.h reload.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-recog.c \ + $(OUTPUT_OPTION) + +insn-recog.c: s-recog ; @true +s-recog : $(md_file) genrecog$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genrecog$(build_exeext) $(md_file) > tmp-recog.c + $(SHELL) $(srcdir)/move-if-change tmp-recog.c insn-recog.c + $(STAMP) s-recog + +insn-opinit.o : insn-opinit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) insn-config.h flags.h $(RECOG_H) $(EXPR_H) $(OPTABS_H) reload.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-opinit.c \ + $(OUTPUT_OPTION) + +insn-opinit.c: s-opinit ; @true +s-opinit : $(md_file) genopinit$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genopinit$(build_exeext) $(md_file) > tmp-opinit.c + $(SHELL) $(srcdir)/move-if-change tmp-opinit.c insn-opinit.c + $(STAMP) s-opinit + +insn-extract.o : insn-extract.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) toplev.h insn-config.h $(RECOG_H) + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-extract.c \ + $(OUTPUT_OPTION) + +insn-extract.c: s-extract ; @true +s-extract : $(md_file) genextract$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genextract$(build_exeext) $(md_file) > tmp-extract.c + $(SHELL) $(srcdir)/move-if-change tmp-extract.c insn-extract.c + $(STAMP) s-extract + +insn-peep.o : insn-peep.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(REGS_H) output.h real.h insn-config.h $(RECOG_H) except.h \ + function.h $(TM_P_H) + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-peep.c \ + $(OUTPUT_OPTION) + +insn-peep.c: s-peep ; @true +s-peep : $(md_file) genpeep$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genpeep$(build_exeext) $(md_file) > tmp-peep.c + $(SHELL) $(srcdir)/move-if-change tmp-peep.c insn-peep.c + $(STAMP) s-peep + +insn-attrtab.o : insn-attrtab.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(REGS_H) real.h output.h $(INSN_ATTR_H) insn-config.h toplev.h \ + $(RECOG_H) $(TM_P_H) flags.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-attrtab.c \ + $(OUTPUT_OPTION) + +insn-attr.h: s-attr ; @true +s-attr : $(md_file) genattr$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genattr$(build_exeext) $(md_file) > tmp-attr.h + $(SHELL) $(srcdir)/move-if-change tmp-attr.h insn-attr.h + $(STAMP) s-attr + +insn-attrtab.c: s-attrtab ; @true +s-attrtab : $(md_file) genattrtab$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genattrtab$(build_exeext) $(md_file) > tmp-attrtab.c + $(SHELL) $(srcdir)/move-if-change tmp-attrtab.c insn-attrtab.c + $(STAMP) s-attrtab + +insn-output.o : insn-output.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(GGC_H) $(REGS_H) real.h conditions.h hard-reg-set.h \ + insn-config.h $(INSN_ATTR_H) $(EXPR_H) output.h $(RECOG_H) function.h \ + toplev.h flags.h insn-codes.h $(TM_P_H) $(TARGET_H) + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-output.c \ + $(OUTPUT_OPTION) + +insn-output.c: s-output ; @true +s-output : $(md_file) genoutput$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genoutput$(build_exeext) $(md_file) > tmp-output.c + $(SHELL) $(srcdir)/move-if-change tmp-output.c insn-output.c + $(STAMP) s-output + +genrtl.o : genrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + $(GGC_H) +genrtl.c genrtl.h : s-genrtl + @true # force gnu make to recheck modification times. + +s-genrtl: gengenrtl$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./gengenrtl$(build_exeext) -h > tmp-genrtl.h + $(SHELL) $(srcdir)/move-if-change tmp-genrtl.h genrtl.h + $(RUN_GEN) ./gengenrtl$(build_exeext) > tmp-genrtl.c + $(SHELL) $(srcdir)/move-if-change tmp-genrtl.c genrtl.c $(STAMP) s-genrtl -s-genrtl-h: build/gengenrtl$(build_exeext) - $(RUN_GEN) build/gengenrtl$(build_exeext) -h > tmp-genrtl.h - $(SHELL) $(srcdir)/../move-if-change tmp-genrtl.h genrtl.h - $(STAMP) s-genrtl-h - -insn-modes.c: s-modes; @true -insn-modes.h: s-modes-h; @true -min-insn-modes.c: s-modes-m; @true - -s-modes: build/genmodes$(build_exeext) - $(RUN_GEN) build/genmodes$(build_exeext) > tmp-modes.c - $(SHELL) $(srcdir)/../move-if-change tmp-modes.c insn-modes.c +insn-modes.o : insn-modes.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(MACHMODE_H) real.h +min-insn-modes.c insn-modes.c insn-modes.h : s-modes ; @true + +s-modes: genmodes$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genmodes$(build_exeext) -h > tmp-modes.h + $(SHELL) $(srcdir)/move-if-change tmp-modes.h insn-modes.h + $(RUN_GEN) ./genmodes$(build_exeext) -m > tmp-min-modes.c + $(SHELL) $(srcdir)/move-if-change tmp-min-modes.c min-insn-modes.c + $(RUN_GEN) ./genmodes$(build_exeext) > tmp-modes.c + $(SHELL) $(srcdir)/move-if-change tmp-modes.c insn-modes.c $(STAMP) s-modes -s-modes-h: build/genmodes$(build_exeext) - $(RUN_GEN) build/genmodes$(build_exeext) -h > tmp-modes.h - $(SHELL) $(srcdir)/../move-if-change tmp-modes.h insn-modes.h - $(STAMP) s-modes-h - -s-modes-m: build/genmodes$(build_exeext) - $(RUN_GEN) build/genmodes$(build_exeext) -m > tmp-min-modes.c - $(SHELL) $(srcdir)/../move-if-change tmp-min-modes.c min-insn-modes.c - $(STAMP) s-modes-m +tm-preds.h: s-preds; @true -insn-preds.c: s-preds; @true -tm-preds.h: s-preds-h; @true -tm-constrs.h: s-constrs-h; @true - -s-preds: $(MD_DEPS) build/genpreds$(build_exeext) - $(RUN_GEN) build/genpreds$(build_exeext) $(md_file) > tmp-preds.c - $(SHELL) $(srcdir)/../move-if-change tmp-preds.c insn-preds.c +s-preds: genpreds$(build_exeext) $(srcdir)/move-if-change + $(RUN_GEN) ./genpreds$(build_exeext) > tmp-preds.h + $(SHELL) $(srcdir)/move-if-change tmp-preds.h tm-preds.h $(STAMP) s-preds -s-preds-h: $(MD_DEPS) build/genpreds$(build_exeext) - $(RUN_GEN) build/genpreds$(build_exeext) -h $(md_file) > tmp-preds.h - $(SHELL) $(srcdir)/../move-if-change tmp-preds.h tm-preds.h - $(STAMP) s-preds-h - -s-constrs-h: $(MD_DEPS) build/genpreds$(build_exeext) - $(RUN_GEN) build/genpreds$(build_exeext) -c $(md_file) > tmp-constrs.h - $(SHELL) $(srcdir)/../move-if-change tmp-constrs.h tm-constrs.h - $(STAMP) s-constrs-h - -GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \ - $(CPP_ID_DATA_H) $(host_xm_file_list) \ - $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) $(srcdir)/bitmap.h \ - $(srcdir)/coverage.c $(srcdir)/rtl.h \ - $(srcdir)/optabs.h $(srcdir)/tree.h $(srcdir)/function.h $(srcdir)/libfuncs.h $(SYMTAB_H) \ - $(srcdir)/real.h $(srcdir)/varray.h $(srcdir)/insn-addr.h $(srcdir)/hwint.h \ - $(srcdir)/ipa-reference.h $(srcdir)/output.h \ +GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h $(srcdir)/cpplib.h \ + $(host_xm_file_list) $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) \ + $(srcdir)/bitmap.h $(srcdir)/coverage.c $(srcdir)/function.h $(srcdir)/rtl.h \ + $(srcdir)/optabs.h $(srcdir)/tree.h $(srcdir)/libfuncs.h $(srcdir)/hashtable.h \ + $(srcdir)/real.h $(srcdir)/varray.h $(srcdir)/insn-addr.h \ $(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/cgraph.h \ - $(srcdir)/c-common.h $(srcdir)/c-tree.h $(srcdir)/reload.h \ + $(srcdir)/c-common.h $(srcdir)/c-tree.h \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \ - $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-inline.c \ $(srcdir)/dbxout.c $(srcdir)/dwarf2out.c $(srcdir)/dwarf2asm.c \ - $(srcdir)/dojump.c $(srcdir)/tree-profile.c \ + $(srcdir)/dojump.c \ $(srcdir)/emit-rtl.c $(srcdir)/except.c $(srcdir)/explow.c $(srcdir)/expr.c \ - $(srcdir)/function.c $(srcdir)/except.h \ + $(srcdir)/fold-const.c $(srcdir)/function.c \ $(srcdir)/gcse.c $(srcdir)/integrate.c $(srcdir)/lists.c $(srcdir)/optabs.c \ - $(srcdir)/profile.c $(srcdir)/regclass.c \ - $(srcdir)/reg-stack.c $(srcdir)/cfglayout.c \ - $(srcdir)/sdbout.c $(srcdir)/stor-layout.c \ + $(srcdir)/profile.c $(srcdir)/ra-build.c $(srcdir)/regclass.c \ + $(srcdir)/reg-stack.c $(srcdir)/cfglayout.c $(srcdir)/langhooks.c \ + $(srcdir)/sdbout.c $(srcdir)/stmt.c $(srcdir)/stor-layout.c \ $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \ - $(srcdir)/tree-mudflap.c $(srcdir)/tree-flow.h \ - $(srcdir)/c-objc-common.c $(srcdir)/c-common.c $(srcdir)/c-parser.c \ - $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c $(srcdir)/tree-ssa-address.c \ - $(srcdir)/tree-phinodes.c $(srcdir)/tree-cfg.c \ - $(srcdir)/tree-dfa.c $(srcdir)/tree-ssa-propagate.c \ - $(srcdir)/tree-iterator.c $(srcdir)/gimplify.c \ - $(srcdir)/tree-chrec.h $(srcdir)/tree-vect-generic.c \ - $(srcdir)/tree-ssa-operands.h $(srcdir)/tree-ssa-operands.c \ - $(srcdir)/tree-profile.c $(srcdir)/tree-nested.c \ - $(srcdir)/ipa-reference.c $(srcdir)/tree-ssa-structalias.h \ - $(srcdir)/tree-ssa-structalias.c \ - $(srcdir)/c-pragma.h $(srcdir)/omp-low.c \ - $(srcdir)/targhooks.c $(srcdir)/cgraphunit.c $(out_file) \ + $(out_file) \ @all_gtfiles@ GTFILES_FILES_LANGS = @all_gtfiles_files_langs@ @@ -2879,182 +2101,241 @@ GTFILES_FILES_FILES = @all_gtfiles_files_files@ GTFILES_LANG_DIR_NAMES = @subdirs@ GTFILES_SRCDIR = @srcdir@ -GTFILES_FILES_FILES_C = $(subst $(srcdir)/,, \ - $(filter %.c, $(GTFILES_FILES_FILES))) -GTFILES_FILES_FILES_H = $(addprefix gt-, \ - $(subst /,-,$(GTFILES_FILES_FILES_C:.c=.h))) -GTFILES_LANG_DIR_NAMES_H = $(foreach d,$(GTFILES_LANG_DIR_NAMES), gtype-$(d).h) -ALL_GTFILES_H := $(sort $(GTFILES_FILES_FILES_H) $(GTFILES_LANG_DIR_NAMES_H)) - -$(ALL_GTFILES_H) : s-gtype ; @true - - gt-cgraph.h gt-coverage.h gtype-desc.h gtype-desc.c gt-except.h \ -gt-function.h gt-integrate.h gt-tree.h gt-varasm.h \ +gt-function.h gt-integrate.h gt-stmt.h gt-tree.h gt-varasm.h \ gt-emit-rtl.h gt-explow.h gt-stor-layout.h gt-regclass.h \ -gt-lists.h gt-alias.h gt-cselib.h gt-gcse.h \ +gt-lists.h gt-alias.h gt-cselib.h gt-fold-const.h gt-gcse.h \ gt-expr.h gt-sdbout.h gt-optabs.h gt-bitmap.h gt-dojump.h \ -gt-dwarf2out.h gt-dwarf2asm.h \ -gt-dbxout.h \ -gtype-c.h gt-cfglayout.h \ -gt-tree-mudflap.h gt-tree-vect-generic.h \ -gt-tree-profile.h gt-tree-ssa-address.h \ -gt-tree-ssanames.h gt-tree-iterator.h gt-gimplify.h \ -gt-tree-phinodes.h gt-tree-nested.h \ -gt-tree-ssa-operands.h gt-tree-ssa-propagate.h \ -gt-tree-ssa-structalias.h gt-ipa-inline.h gt-cgraphunit.h \ -gt-stringpool.h gt-targhooks.h gt-omp-low.h : s-gtype ; @true - -define echo_quoted_to_gtyp - echo "\"$(gtyp)\", " >> tmp-gtyp.h - -endef - -gtyp-gen.h: s-gtyp-gen ; @true -s-gtyp-gen: Makefile +gt-dwarf2out.h gt-ra-build.h gt-reg-stack.h gt-dwarf2asm.h \ +gt-dbxout.h gt-c-common.h gt-c-decl.h gt-c-parse.h \ +gt-c-pragma.h gtype-c.h gt-input.h gt-cfglayout.h \ +gt-stringpool.h gt-langhooks.h : s-gtype ; @true + +gtyp-gen.h: Makefile echo "/* This file is machine generated. Do not edit. */" > tmp-gtyp.h echo "static const char *const srcdir = " >> tmp-gtyp.h echo "\"$(GTFILES_SRCDIR)\"" >> tmp-gtyp.h echo ";" >> tmp-gtyp.h echo "static const char *const lang_files[] = {" >> tmp-gtyp.h - $(foreach gtyp,$(GTFILES_FILES_FILES),$(echo_quoted_to_gtyp)) + ll="$(GTFILES_FILES_FILES)"; \ + for f in $$ll; do \ + echo "\"$$f\", "; done >> tmp-gtyp.h echo "NULL};" >> tmp-gtyp.h echo "static const char *const langs_for_lang_files[] = {" >> tmp-gtyp.h - $(foreach gtyp,$(GTFILES_FILES_LANGS),$(echo_quoted_to_gtyp)) + ff="$(GTFILES_FILES_LANGS)"; \ + for f in $$ff; do \ + echo "\"$$f\", " ; done >> tmp-gtyp.h echo "NULL};" >> tmp-gtyp.h echo "static const char *const all_files[] = {" >> tmp-gtyp.h - $(foreach gtyp,$(GTFILES),$(echo_quoted_to_gtyp)) + gf="$(GTFILES)"; \ + for f in $$gf; do \ + echo "\"$$f\", "; done >> tmp-gtyp.h echo " NULL};" >> tmp-gtyp.h echo "static const char *const lang_dir_names[] = { \"c\", " >> tmp-gtyp.h - $(foreach gtyp,$(GTFILES_LANG_DIR_NAMES),$(echo_quoted_to_gtyp)) + gf="$(GTFILES_LANG_DIR_NAMES)"; \ + for l in $$gf; do \ + echo "\"$$l\", "; done >> tmp-gtyp.h echo "NULL};" >> tmp-gtyp.h - $(SHELL) $(srcdir)/../move-if-change tmp-gtyp.h gtyp-gen.h - $(STAMP) s-gtyp-gen + $(SHELL) $(srcdir)/move-if-change tmp-gtyp.h gtyp-gen.h -s-gtype: build/gengtype$(build_exeext) $(GTFILES) - $(RUN_GEN) build/gengtype$(build_exeext) +s-gtype: gengtype$(build_exeext) $(GTFILES) + $(RUN_GEN) ./gengtype $(STAMP) s-gtype # -# How to compile object files to run on the build machine. +# Compile the programs that generate insn-* from the machine description. +# They are compiled with $(CC_FOR_BUILD), and associated libraries, +# since they need to run on this machine +# even if GCC is being compiled to run on some other machine. -build/%.o : # dependencies provided by explicit rule later - $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) -o $@ $< +# $(CONFIG_H) is omitted from the deps of the gen*.o +# because these programs don't really depend on anything +# about the target machine. They do depend on config.h itself, +# since that describes the host machine. -# Header dependencies for the programs that generate source code. -# These are library modules... -build/errors.o : errors.c $(BCONFIG_H) $(SYSTEM_H) errors.h -build/gensupport.o: gensupport.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ - $(GTM_H) $(RTL_BASE_H) $(OBSTACK_H) errors.h $(HASHTAB_H) \ - gensupport.h -build/ggc-none.o : ggc-none.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ - $(GGC_H) -build/min-insn-modes.o : min-insn-modes.c $(BCONFIG_H) $(SYSTEM_H) \ - $(MACHMODE_H) -build/print-rtl.o: print-rtl.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ - $(GTM_H) $(RTL_BASE_H) -build/read-rtl.o: read-rtl.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ - $(GTM_H) $(RTL_BASE_H) $(OBSTACK_H) $(HASHTAB_H) gensupport.h -build/rtl.o: rtl.c $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H) \ - $(RTL_H) $(REAL_H) $(GGC_H) errors.h -build/vec.o : vec.c $(BCONFIG_H) $(SYSTEM_H) $(TREE_H) coretypes.h vec.h \ - $(GGC_H) toplev.h -build/gencondmd.o : build/gencondmd.c $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) insn-constants.h $(RTL_H) $(TM_P_H) \ - $(FUNCTION_H) $(REGS_H) $(RECOG_H) $(REAL_H) output.h $(FLAGS_H) \ - $(RESOURCE_H) toplev.h reload.h except.h tm-constrs.h -# This pulls in tm-pred.h which contains inline functions wrapping up -# predicates from the back-end so those functions must be discarded. -# No big deal since gencondmd.c is a dummy file for non-GCC compilers. -build/gencondmd.o : \ - BUILD_CFLAGS := $(filter-out -fkeep-inline-functions, $(BUILD_CFLAGS)) - -# ...these are the programs themselves. -build/genattr.o : genattr.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) errors.h gensupport.h -build/genattrtab.o : genattrtab.c $(RTL_BASE_H) $(OBSTACK_H) \ - $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) errors.h $(GGC_H) \ +# The names of programs that run on the "build" machine. +genprognames=genconfig genflags gencodes genemit genopinit genrecog \ + genextract genpeep genattr genoutput + +# The names of the executable files for those programs. +genprogs=$(genprognames:%=%$(build_exeext)) + +# Object files used in those programs. +genobjs=$(genprognames:%=%.o) read-rtl.o gensupport.o genattrtab.o \ + genautomata.o gengenrtl.o genmodes.o genpreds.o gengtype.o \ + genconstants.o gen-protos.o scan.o fix-header.o scan-decls.o \ + gencheck.o dummy-conditions.o genconditions.o + +$(genprogs): %$(build_exeext): %.o $(BUILD_RTL) $(BUILD_SUPPORT) \ + $(BUILD_PRINT) $(BUILD_ERRORS) \ + $(BUILD_LIBDEPS) + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ + $< $(BUILD_RTL) $(BUILD_SUPPORT) $(BUILD_PRINT) \ + $(BUILD_ERRORS) $(BUILD_LIBS) + +$(genobjs): %.o : %.c + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +read-rtl.o: read-rtl.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) $(RTL_H) \ + $(OBSTACK_H) $(HASHTAB_H) + +gensupport.o: gensupport.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) $(RTL_H) \ + $(OBSTACK_H) errors.h $(HASHTAB_H) gensupport.h + +genconfig.o : genconfig.c $(RTL_H) $(BCONFIG_H) \ + $(SYSTEM_H) coretypes.h $(GTM_H) errors.h gensupport.h + +genflags.o : genflags.c $(RTL_H) $(OBSTACK_H) $(BCONFIG_H) \ + $(SYSTEM_H) coretypes.h $(GTM_H) errors.h gensupport.h + +gencodes.o : gencodes.c $(RTL_H) $(BCONFIG_H) \ + $(SYSTEM_H) coretypes.h $(GTM_H) errors.h gensupport.h + +genconstants$(build_exeext) : genconstants.o $(BUILD_RTL) $(BUILD_EARLY_SUPPORT) \ + $(BUILD_ERRORS) $(BUILD_LIBDEPS) + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ + genconstants.o $(BUILD_EARLY_SUPPORT) $(BUILD_RTL) \ + $(BUILD_ERRORS) $(BUILD_LIBS) + +genconstants.o : genconstants.c $(RTL_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) \ + errors.h + +genemit.o : genemit.c $(RTL_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) \ + errors.h gensupport.h + +genopinit.o : genopinit.c $(RTL_H) $(BCONFIG_H) \ + $(SYSTEM_H) coretypes.h $(GTM_H) errors.h gensupport.h + +genrecog.o : genrecog.c $(RTL_H) $(BCONFIG_H) \ + $(SYSTEM_H) coretypes.h $(GTM_H) errors.h gensupport.h + +genextract.o : genextract.c $(RTL_H) $(BCONFIG_H) \ + $(SYSTEM_H) coretypes.h $(GTM_H) insn-config.h errors.h gensupport.h + +genpeep.o : genpeep.c $(RTL_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) \ + errors.h gensupport.h + +genattr.o : genattr.c $(RTL_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) errors.h \ gensupport.h -build/genautomata.o : genautomata.c $(RTL_BASE_H) $(OBSTACK_H) \ - $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) errors.h vec.h \ - $(HASHTAB_H) gensupport.h -build/gencheck.o : gencheck.c gencheck.h tree.def $(BCONFIG_H) $(GTM_H) \ - $(SYSTEM_H) coretypes.h $(lang_tree_files) -build/genchecksum.o : genchecksum.c $(BCONFIG_H) $(SYSTEM_H) $(MD5_H) -build/gencodes.o : gencodes.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) errors.h gensupport.h -build/genconditions.o : genconditions.c $(RTL_BASE_H) $(BCONFIG_H) \ - $(SYSTEM_H) coretypes.h $(GTM_H) errors.h -build/genconfig.o : genconfig.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) errors.h gensupport.h -build/genconstants.o : genconstants.c $(RTL_BASE_H) $(BCONFIG_H) \ - $(SYSTEM_H) coretypes.h $(GTM_H) errors.h -build/genemit.o : genemit.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) errors.h gensupport.h -build/genextract.o : genextract.c $(RTL_BASE_H) $(BCONFIG_H) \ - $(SYSTEM_H) coretypes.h $(GTM_H) errors.h gensupport.h vecprim.h -build/genflags.o : genflags.c $(RTL_BASE_H) $(OBSTACK_H) $(BCONFIG_H) \ + +genattrtab$(build_exeext) : genattrtab.o genautomata.o \ + $(BUILD_RTL) $(BUILD_SUPPORT) $(BUILD_PRINT) $(BUILD_ERRORS) $(BUILD_VARRAY) \ + $(BUILD_LIBDEPS) + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ + genattrtab.o genautomata.o \ + $(BUILD_RTL) $(BUILD_SUPPORT) $(BUILD_PRINT) $(BUILD_ERRORS) \ + $(BUILD_VARRAY) $(BUILD_LIBS) -lm + +genattrtab.o : genattrtab.c $(RTL_H) $(OBSTACK_H) $(BCONFIG_H) \ + $(SYSTEM_H) coretypes.h $(GTM_H) errors.h $(GGC_H) gensupport.h genattrtab.h + +genautomata.o : genautomata.c $(RTL_H) $(OBSTACK_H) $(BCONFIG_H) \ + $(SYSTEM_H) coretypes.h $(GTM_H) errors.h varray.h genattrtab.h $(HASHTAB_H) + +genoutput.o : genoutput.c $(RTL_H) $(BCONFIG_H) \ $(SYSTEM_H) coretypes.h $(GTM_H) errors.h gensupport.h -build/gengenrtl.o : gengenrtl.c $(BCONFIG_H) $(SYSTEM_H) rtl.def -build/gengtype-lex.o : gengtype-lex.c gengtype.h gengtype-yacc.h \ - $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H) vec.h -build/gengtype-yacc.o : gengtype-yacc.c gengtype.h $(BCONFIG_H) \ - $(SYSTEM_H) coretypes.h $(GTM_H) -build/gengtype.o : gengtype.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ - $(GTM_H) gengtype.h gtyp-gen.h rtl.def insn-notes.def errors.h -build/genmddeps.o: genmddeps.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ - $(GTM_H) $(RTL_BASE_H) errors.h gensupport.h -build/genmodes.o : genmodes.c $(BCONFIG_H) $(SYSTEM_H) errors.h \ - $(HASHTAB_H) machmode.def $(extra_modes_file) -build/genopinit.o : genopinit.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) errors.h gensupport.h -build/genoutput.o : genoutput.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) errors.h gensupport.h -build/genpeep.o : genpeep.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) errors.h gensupport.h toplev.h -build/genpreds.o : genpreds.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) errors.h gensupport.h $(OBSTACK_H) -build/genrecog.o : genrecog.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) errors.h gensupport.h -# Compile the programs that generate insn-* from the machine description. -# They are compiled with $(CC_FOR_BUILD), and associated libraries, -# since they need to run on this machine -# even if GCC is being compiled to run on some other machine. +gengenrtl$(build_exeext) : gengenrtl.o $(BUILD_LIBDEPS) + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ + gengenrtl.o $(BUILD_LIBS) + +gengenrtl.o : gengenrtl.c $(BCONFIG_H) $(SYSTEM_H) rtl.def + +genmodes$(build_exeext) : genmodes.o $(BUILD_ERRORS) $(BUILD_LIBDEPS) + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ + genmodes.o $(BUILD_ERRORS) $(BUILD_LIBS) + +genmodes.o : genmodes.c $(BCONFIG_H) $(SYSTEM_H) errors.h $(HASHTAB_H) \ + machmode.def $(extra_modes_file) + +genpreds$(build_exeext) : genpreds.o $(BUILD_LIBDEPS) + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ + genpreds.o $(BUILD_LIBS) -# As a general rule... -build/gen%$(build_exeext): build/gen%.o $(BUILD_LIBDEPS) +genpreds.o : genpreds.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) + +gengtype$(build_exeext) : gengtype.o gengtype-lex.o gengtype-yacc.o \ + $(BUILD_LIBDEPS) $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ - $(filter-out $(BUILD_LIBDEPS), $^) $(BUILD_LIBS) + gengtype.o gengtype-lex.o gengtype-yacc.o $(BUILD_LIBS) -# All these programs use the MD reader ($(BUILD_RTL)). -genprogmd = attr attrtab automata codes conditions config constants emit \ - extract flags mddeps opinit output peep preds recog -$(genprogmd:%=build/gen%$(build_exeext)): $(BUILD_RTL) $(BUILD_ERRORS) +gengtype.o : gengtype.c gengtype.h $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) \ + real.h $(RTL_BASE_H) gtyp-gen.h -# These programs need libs over and above what they get from the above list. -build/genautomata$(build_exeext) : BUILD_LIBS += -lm +gengtype-lex.o : gengtype-lex.c gengtype.h gengtype-yacc.h \ + $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H) + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) \ + $< $(OUTPUT_OPTION) -# These programs are not linked with the MD reader. -build/gengenrtl$(build_exeext) : $(BUILD_ERRORS) -build/genmodes$(build_exeext) : $(BUILD_ERRORS) -build/gengtype$(build_exeext) : build/gengtype-lex.o \ - build/gengtype-yacc.o $(BUILD_ERRORS) +gengtype-yacc.o : gengtype-yacc.c gengtype.h $(BCONFIG_H) $(SYSTEM_H) \ + coretypes.h $(GTM_H) + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) \ + $< $(OUTPUT_OPTION) -# Generated source files for gengtype. gengtype-lex.c : gengtype-lex.l -$(FLEX) $(FLEXFLAGS) -o$@ $< -# This is a pattern rule solely so that Make knows it need not run the -# command twice. The modifier to $@ ensures that Bison is asked to -# produce a .c file, whether or not Make decides it needs the .h file -# first. -gengtype-y%.c gengtype-y%.h: gengtype-y%.y - -$(BISON) $(BISONFLAGS) -d -o $(@:.h=.c) $< + +gengtype-yacc.c gengtype-yacc.h: gengtype-yacc.y + -$(BISON) $(BISONFLAGS) -d -o gengtype-yacc.c $< + +genconditions$(build_exeext) : genconditions.o $(BUILD_EARLY_SUPPORT) \ + $(BUILD_RTL) $(BUILD_ERRORS) $(BUILD_LIBDEPS) + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ + genconditions.o $(BUILD_EARLY_SUPPORT) $(BUILD_RTL) \ + $(BUILD_ERRORS) $(BUILD_LIBS) + +genconditions.o : genconditions.c $(RTL_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ + $(GTM_H) errors.h + +# +# Compile the libraries to be used by gen*. +# If we are not cross-building, gen* use the same .o's that cc1 will use, +# and BUILD_PREFIX_1 is `loser-', just to ensure these rules don't conflict +# with the rules for rtl.o, etc. +$(BUILD_PREFIX_1)rtl.o: $(srcdir)/rtl.c $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H) $(RTL_H) \ + real.h $(GGC_H) errors.h + rm -f $(BUILD_PREFIX)rtl.c + sed -e 's/config[.]h/bconfig.h/' $(srcdir)/rtl.c > $(BUILD_PREFIX)rtl.c + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) $(BUILD_PREFIX)rtl.c $(OUTPUT_OPTION) + +print-rtl1.o: $(srcdir)/print-rtl.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ + $(GTM_H) $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TM_P_H) + rm -f print-rtl1.c + sed -e 's/config[.]h/bconfig.h/' $(srcdir)/print-rtl.c > print-rtl1.c + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) print-rtl1.c $(OUTPUT_OPTION) + +$(BUILD_PREFIX_1)bitmap.o: $(srcdir)/bitmap.c $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H) \ + $(RTL_H) flags.h $(BASIC_BLOCK_H) $(REGS_H) $(GGC_H) + rm -f $(BUILD_PREFIX)bitmap.c + sed -e 's/config[.]h/bconfig.h/' $(srcdir)/bitmap.c > $(BUILD_PREFIX)bitmap.c + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) $(BUILD_PREFIX)bitmap.c $(OUTPUT_OPTION) + +$(BUILD_PREFIX_1)errors.o: errors.c $(BCONFIG_H) $(SYSTEM_H) errors.h + rm -f $(BUILD_PREFIX)errors.c + sed -e 's/config[.]h/bconfig.h/' $(srcdir)/errors.c > $(BUILD_PREFIX)errors.c + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) $(BUILD_PREFIX)errors.c $(OUTPUT_OPTION) + +$(BUILD_PREFIX_1)varray.o: varray.c $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H) varray.h \ + $(RTL_H) $(GGC_H) $(TREE_H) bitmap.h errors.h + rm -f $(BUILD_PREFIX)varray.c + sed -e 's/config[.]h/bconfig.h/' $(srcdir)/varray.c > \ + $(BUILD_PREFIX)varray.c + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) \ + $(BUILD_PREFIX)varray.c $(OUTPUT_OPTION) + +$(BUILD_PREFIX_1)ggc-none.o: ggc-none.c $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H) $(GGC_H) + rm -f $(BUILD_PREFIX)ggc-none.c + sed -e 's/config[.]h/bconfig.h/' $(srcdir)/ggc-none.c > $(BUILD_PREFIX)ggc-none.c + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) $(BUILD_PREFIX)ggc-none.c $(OUTPUT_OPTION) + +min-insn-modes.o: min-insn-modes.c $(BCONFIG_H) $(SYSTEM_H) $(MACHMODE_H) + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) \ + min-insn-modes.c $(OUTPUT_OPTION) # # Remake internationalization support. intl.o: intl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) intl.h Makefile - $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ -DLOCALEDIR=\"$(localedir)\" \ -c $(srcdir)/intl.c $(OUTPUT_OPTION) @@ -3071,18 +2352,48 @@ PREPROCESSOR_DEFINES = \ -DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\" \ @TARGET_SYSTEM_ROOT_DEFINE@ +LIBCPP_OBJS = cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o cpptrad.o \ + cpphash.o cpperror.o cppinit.o cppcharset.o \ + hashtable.o line-map.o mkdeps.o cpppch.o + +LIBCPP_DEPS = $(CPPLIB_H) cpphash.h line-map.h hashtable.h intl.h \ + $(OBSTACK_H) $(CONFIG_H) $(SYSTEM_H) + +# Most of the other archives built/used by this makefile are for +# targets. This one is strictly for the host. +libcpp.a: $(LIBCPP_OBJS) + -rm -rf libcpp.a + $(AR) $(AR_FLAGS) libcpp.a $(LIBCPP_OBJS) + -$(RANLIB) libcpp.a + +cppcharset.o: cppcharset.c $(LIBCPP_DEPS) cppucnid.h +cpperror.o: cpperror.c $(LIBCPP_DEPS) +cppexp.o: cppexp.c $(LIBCPP_DEPS) +cpplex.o: cpplex.c $(LIBCPP_DEPS) +cppmacro.o: cppmacro.c $(LIBCPP_DEPS) +cpplib.o: cpplib.c $(LIBCPP_DEPS) +cpphash.o: cpphash.c $(LIBCPP_DEPS) +cpptrad.o: cpptrad.c $(LIBCPP_DEPS) +cppfiles.o: cppfiles.c $(LIBCPP_DEPS) $(HASHTAB_H) mkdeps.h +cppinit.o: cppinit.c $(LIBCPP_DEPS) mkdeps.h +cpppch.o: cpppch.c $(LIBCPP_DEPS) mkdeps.h + cppdefault.o: cppdefault.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ cppdefault.h Makefile - $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(PREPROCESSOR_DEFINES) \ -c $(srcdir)/cppdefault.c $(OUTPUT_OPTION) +mkdeps.o: mkdeps.c $(CONFIG_H) $(SYSTEM_H) mkdeps.h +hashtable.o: hashtable.c hashtable.h $(CONFIG_H) $(SYSTEM_H) $(OBSTACK_H) +line-map.o: line-map.c line-map.h intl.h $(CONFIG_H) $(SYSTEM_H) + # Note for the stamp targets, we run the program `true' instead of # having an empty command (nothing following the semicolon). proto: config.status protoize$(exeext) unprotoize$(exeext) SYSCALLS.c.X -PROTO_OBJS = intl.o version.o cppdefault.o errors.o +PROTO_OBJS = intl.o version.o cppdefault.o protoize$(exeext): protoize.o $(PROTO_OBJS) $(LIBDEPS) $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ protoize.o $(PROTO_OBJS) $(LIBS) @@ -3091,18 +2402,18 @@ unprotoize$(exeext): unprotoize.o $(PROTO_OBJS) $(LIBDEPS) $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ unprotoize.o $(PROTO_OBJS) $(LIBS) protoize.o: protoize.c $(srcdir)/../include/getopt.h $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) Makefile version.h cppdefault.h intl.h + coretypes.h $(TM_H) Makefile version.h (SHLIB_LINK='$(SHLIB_LINK)' \ SHLIB_MULTILIB='$(SHLIB_MULTILIB)'; \ - $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(DRIVER_DEFINES) \ $(srcdir)/protoize.c $(OUTPUT_OPTION)) -unprotoize.o: protoize.c $(srcdir)/../include/getopt.h $(CONFIG_H) \ - $(SYSTEM_H) coretypes.h $(TM_H) Makefile version.h cppdefault.h intl.h +unprotoize.o: protoize.c $(srcdir)/../include/getopt.h \ + $(CONFIG_H) $(SYSTEM_H) Makefile version.h (SHLIB_LINK='$(SHLIB_LINK)' \ SHLIB_MULTILIB='$(SHLIB_MULTILIB)'; \ - $(CC) -c -DUNPROTOIZE $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(CC) -c -DUNPROTOIZE $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(DRIVER_DEFINES) \ $(srcdir)/protoize.c $(OUTPUT_OPTION)) @@ -3112,7 +2423,7 @@ SYSCALLS.c.X: $(srcdir)/sys-types.h $(srcdir)/sys-protos.h $(GCC_PASSES) \ -rm -f SYSCALLS.c tmp-SYSCALLS.s sed -e s/TARGET_GETGROUPS_T/$(TARGET_GETGROUPS_T)/ \ $(srcdir)/sys-types.h $(srcdir)/sys-protos.h > SYSCALLS.c - $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) \ + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ -aux-info $@ -S -o tmp-SYSCALLS.s SYSCALLS.c -rm -f SYSCALLS.c tmp-SYSCALLS.s @@ -3147,28 +2458,25 @@ test-protoize-simple: ./protoize ./unprotoize $(GCC_PASSES) -rm -f tmp-proto.[cs] tmp-proto$(objext) # gcov-iov.c is run on the build machine to generate gcov-iov.h from version.c -build/gcov-iov.o: gcov-iov.c $(BCONFIG_H) coretypes.h $(GTM_H) \ - $(SYSTEM_H) coretypes.h $(TM_H) - -build/gcov-iov$(build_exeext): build/gcov-iov.o - $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) build/gcov-iov.o -o $@ - +gcov-iov.o: gcov-iov.c version.c $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H) coretypes.h $(TM_H) + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) $(srcdir)/gcov-iov.c $(OUTPUT_OPTION) +gcov-iov$(build_exeext): gcov-iov.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) gcov-iov.o -o $@ gcov-iov.h: s-iov -s-iov: build/gcov-iov$(build_exeext) $(BASEVER) $(DEVPHASE) - build/gcov-iov$(build_exeext) '$(BASEVER_c)' '$(DEVPHASE_c)' \ - > tmp-gcov-iov.h - $(SHELL) $(srcdir)/../move-if-change tmp-gcov-iov.h gcov-iov.h +s-iov: gcov-iov$(build_exeext) $(srcdir)/move-if-change + ./gcov-iov$(build_exeext) > tmp-gcov-iov.h + $(SHELL) $(srcdir)/move-if-change tmp-gcov-iov.h gcov-iov.h $(STAMP) s-iov -gcov.o: gcov.c gcov-io.c $(GCOV_IO_H) intl.h $(SYSTEM_H) coretypes.h $(TM_H) \ - $(CONFIG_H) version.h -gcov-dump.o: gcov-dump.c gcov-io.c $(GCOV_IO_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(CONFIG_H) +gcov.o: gcov.c gcov-io.h gcov-io.c gcov-iov.h intl.h $(SYSTEM_H) coretypes.h $(TM_H) $(CONFIG_H) +gcov-dump.o: gcov-dump.c gcov-io.h gcov-io.c gcov-iov.h $(SYSTEM_H) coretypes.h $(TM_H) $(CONFIG_H) -GCOV_OBJS = gcov.o intl.o version.o errors.o +# Only one of 'gcov' or 'gcov.exe' is actually built, depending +# upon whether $(exeext) is empty or not. +GCOV_OBJS = gcov.o intl.o version.o gcov$(exeext): $(GCOV_OBJS) $(LIBDEPS) $(CC) $(ALL_CFLAGS) $(LDFLAGS) $(GCOV_OBJS) $(LIBS) -o $@ -GCOV_DUMP_OBJS = gcov-dump.o version.o errors.o +GCOV_DUMP_OBJS = gcov-dump.o version.o gcov-dump$(exeext): $(GCOV_DUMP_OBJS) $(LIBDEPS) $(CC) $(ALL_CFLAGS) $(LDFLAGS) $(GCOV_DUMP_OBJS) $(LIBS) -o $@ # @@ -3177,7 +2485,7 @@ gcov-dump$(exeext): $(GCOV_DUMP_OBJS) $(LIBDEPS) # be rebuilt. # Build the include directory -stmp-int-hdrs: $(STMP_FIXINC) $(USER_H) xlimits.h $(UNWIND_H) +stmp-int-hdrs: $(STMP_FIXINC) $(USER_H) xlimits.h # Copy in the headers provided with gcc. # The sed command gets just the last file name component; # this is necessary because VPATH could add a dirname. @@ -3195,76 +2503,64 @@ stmp-int-hdrs: $(STMP_FIXINC) $(USER_H) xlimits.h $(UNWIND_H) done rm -f include/limits.h cp xlimits.h include/limits.h - rm -f include/unwind.h - cp $(UNWIND_H) include/unwind.h chmod a+r include/limits.h # Install the README rm -f include/README - cp $(srcdir)/../fixincludes/README-fixinc include/README + cp $(srcdir)/README-fixinc include/README chmod a+r include/README $(STAMP) $@ +# fixinc.sh depends on this, not on specs directly. +# The idea is to make sure specs gets built, but not rerun fixinc.sh +# after each stage just because specs' mtime has changed. +specs.ready: specs + -if [ -f specs.ready ] ; then \ + true; \ + else \ + $(STAMP) specs.ready; \ + fi + +# Until someone fixes this recursive make nightmare (please note where +# BUILD_CFLAGS and WARN_CFLAGS are first expanded below versus which +# later make invocation has the fine-grain -warn markings for fixinc): +fixinc.sh-warn = -Wno-error + +FIXINCSRCDIR=$(srcdir)/fixinc +fixinc.sh: $(FIXINCSRCDIR)/mkfixinc.sh $(FIXINCSRCDIR)/fixincl.c \ + $(FIXINCSRCDIR)/procopen.c $(FIXINCSRCDIR)/server.c \ + $(FIXINCSRCDIR)/server.h $(FIXINCSRCDIR)/inclhack.def specs.ready + (MAKE="$(MAKE)"; srcdir=`cd $(srcdir)/fixinc && ${PWD_COMMAND}` ; \ + CC="$(CC_FOR_BUILD)"; CFLAGS="$(BUILD_CFLAGS)"; LDFLAGS="$(BUILD_LDFLAGS)"; \ + WARN_CFLAGS="$(WARN_CFLAGS)"; LIBERTY=`${PWD_COMMAND}`/"$(BUILD_LIBIBERTY)"; \ + export MAKE srcdir CC CFLAGS LDFLAGS WARN_CFLAGS LIBERTY; \ + cd ./fixinc && \ + $(SHELL) $${srcdir}/mkfixinc.sh $(build) $(target)) + .PHONY: install-gcc-tooldir install-gcc-tooldir: - $(mkinstalldirs) $(DESTDIR)$(gcc_tooldir) - -macro_list: s-macro_list; @true -s-macro_list : $(GCC_PASSES) - echo | $(GCC_FOR_TARGET) -E -dM - | \ - sed -n -e 's/^#define \([^_][a-zA-Z0-9_]*\).*/\1/p' \ - -e 's/^#define \(_[^_A-Z][a-zA-Z0-9_]*\).*/\1/p' | \ - sort -u > tmp-macro_list - $(SHELL) $(srcdir)/../move-if-change tmp-macro_list macro_list - $(STAMP) s-macro_list - -# The line below is supposed to avoid accidentally matching the -# built-in suffix rule `.o:' to build fixincl out of fixincl.o. You'd -# expect fixincl to be newer than fixincl.o, such that this situation -# would never come up. As it turns out, if you use ccache with -# CCACHE_HARDLINK enabled, the compiler doesn't embed the current -# working directory in object files (-g absent, or -fno-working-dir -# present), and build and host are the same, fixincl for the host will -# build after fixincl for the build machine, getting a cache hit, -# thereby updating the timestamp of fixincl.o in the host tree. -# Because of CCACHE_HARDLINK, this will also update the timestamp in -# the build tree, and so fixincl in the build tree will appear to be -# out of date. Yuck. -../$(build_subdir)/fixincludes/fixincl: ; @ : + $(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(gcc_tooldir) # Build fixed copies of system files. -# Abort if no system headers available, unless building a crosscompiler. -# FIXME: abort unless building --without-headers would be more accurate and less ugly -stmp-fixinc: gsyslimits.h macro_list \ - $(build_objdir)/fixincludes/fixincl \ - $(build_objdir)/fixincludes/fixinc.sh - @if ! $(inhibit_libc) && test ! -d ${SYSTEM_HEADER_DIR}; then \ +stmp-fixinc: fixinc.sh gsyslimits.h + @if test ! -d ${SYSTEM_HEADER_DIR}; then \ echo The directory that should contain system headers does not exist: >&2 ; \ echo " ${SYSTEM_HEADER_DIR}" >&2 ; \ - tooldir_sysinc=`echo "${gcc_tooldir}/sys-include" | sed -e :a -e "s,[^/]*/\.\.\/,," -e ta`; \ - if test "x${SYSTEM_HEADER_DIR}" = "x$${tooldir_sysinc}"; \ + if test "x${SYSTEM_HEADER_DIR}" = "x${gcc_tooldir}/sys-include"; \ then sleep 1; else exit 1; fi; \ fi rm -rf include; mkdir include -chmod a+rx include - if [ -d ../prev-gcc ]; then \ - cd ../prev-gcc && \ - $(MAKE) real-$(INSTALL_HEADERS_DIR) DESTDIR=`pwd`/../gcc/ \ - libsubdir=. ; \ + (TARGET_MACHINE='$(target)'; srcdir=`cd $(srcdir); ${PWD_COMMAND}`; \ + SHELL='$(SHELL)' ;\ + export TARGET_MACHINE srcdir SHELL ; \ + $(SHELL) ./fixinc.sh `${PWD_COMMAND}`/include $(SYSTEM_HEADER_DIR) $(OTHER_FIXINCLUDES_DIRS); \ + rm -f include/syslimits.h; \ + if [ -f include/limits.h ]; then \ + mv include/limits.h include/syslimits.h; \ else \ - (TARGET_MACHINE='$(target)'; srcdir=`cd $(srcdir); ${PWD_COMMAND}`; \ - SHELL='$(SHELL)'; MACRO_LIST=`${PWD_COMMAND}`/macro_list ; \ - export TARGET_MACHINE srcdir SHELL MACRO_LIST && \ - cd $(build_objdir)/fixincludes && \ - $(SHELL) ./fixinc.sh ../../gcc/include \ - $(SYSTEM_HEADER_DIR) $(OTHER_FIXINCLUDES_DIRS) ); \ - rm -f include/syslimits.h; \ - if [ -f include/limits.h ]; then \ - mv include/limits.h include/syslimits.h; \ - else \ - cp $(srcdir)/gsyslimits.h include/syslimits.h; \ - fi; \ - fi - chmod a+r include/syslimits.h + cp $(srcdir)/gsyslimits.h include/syslimits.h; \ + fi; \ + chmod a+r include/syslimits.h) $(STAMP) stmp-fixinc # Files related to the fixproto script. @@ -3283,53 +2579,49 @@ deduced.h: $(GCC_PASSES) $(srcdir)/scan-types.sh stmp-int-hdrs $(STAMP) deduced.h; \ fi -GEN_PROTOS_OBJS = build/gen-protos.o build/scan.o $(BUILD_ERRORS) -build/gen-protos$(build_exeext): $(GEN_PROTOS_OBJS) +GEN_PROTOS_OBJS = gen-protos.o scan.o +gen-protos$(build_exeext): $(GEN_PROTOS_OBJS) ${CC_FOR_BUILD} $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ $(GEN_PROTOS_OBJS) $(BUILD_LIBS) -build/gen-protos.o: gen-protos.c scan.h $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ - $(GTM_H) errors.h +gen-protos.o: gen-protos.c scan.h $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) -build/scan.o: scan.c scan.h $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) +scan.o: scan.c scan.h $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) -xsys-protos.h: $(GCC_PASSES) $(srcdir)/sys-protos.h deduced.h \ - build/gen-protos$(build_exeext) Makefile +xsys-protos.h: $(GCC_PASSES) $(srcdir)/sys-protos.h deduced.h gen-protos$(build_exeext) Makefile sed -e s/TARGET_GETGROUPS_T/$(TARGET_GETGROUPS_T)/ \ deduced.h $(srcdir)/sys-protos.h > tmp-fixtmp.c mv tmp-fixtmp.c fixtmp.c $(GCC_FOR_TARGET) fixtmp.c -w -U__SIZE_TYPE__ -U__PTRDIFF_TYPE__ -U__WCHAR_TYPE__ -E \ | sed -e 's/ / /g' -e 's/ *(/ (/g' -e 's/ [ ]*/ /g' -e 's/( )/()/' \ - | $(RUN_GEN) build/gen-protos >xsys-protos.hT + | $(RUN_GEN) ./gen-protos >xsys-protos.hT mv xsys-protos.hT xsys-protos.h rm -rf fixtmp.c # This is nominally a 'build' program, but it's run only when host==build, # so we can (indeed, must) use $(LIBDEPS) and $(LIBS). -build/fix-header$(build_exeext): build/fix-header.o build/scan-decls.o \ - build/scan.o xsys-protos.h c-incpath.o cppdefault.o prefix.o \ - $(BUILD_ERRORS) $(LIBDEPS) - $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ - build/fix-header.o c-incpath.o cppdefault.o build/scan-decls.o prefix.o \ - build/scan.o $(BUILD_ERRORS) $(LIBS) +fix-header$(build_exeext): fix-header.o scan-decls.o scan.o xsys-protos.h \ + c-incpath.o cppdefault.o prefix.o $(LIBDEPS) libcpp.a + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ fix-header.o \ + c-incpath.o cppdefault.o scan-decls.o prefix.o scan.o libcpp.a $(LIBS) -build/fix-header.o: fix-header.c $(OBSTACK_H) scan.h errors.h \ +fix-header.o: fix-header.c $(OBSTACK_H) scan.h \ xsys-protos.h $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) $(CPPLIB_H) -build/scan-decls.o: scan-decls.c scan.h $(CPPLIB_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) +scan-decls.o: scan-decls.c scan.h $(CPPLIB_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) # stmp-fixproto depends on this, not on fix-header directly. # The idea is to make sure fix-header gets built, # but not rerun fixproto after each stage # just because fix-header's mtime has changed. -fixhdr.ready: build/fix-header$(build_exeext) +fixhdr.ready: fix-header$(build_exeext) -if [ -f fixhdr.ready ] ; then \ true; \ else \ $(STAMP) fixhdr.ready; \ fi -# stmp-int-hdrs is to make sure fixincludes has already finished. +# stmp-int-headers is to make sure fixincludes has already finished. # The if statement is so that we don't run fixproto a second time # if it has already been run on the files in `include'. stmp-fixproto: fixhdr.ready fixproto stmp-int-hdrs @@ -3337,8 +2629,7 @@ stmp-fixproto: fixhdr.ready fixproto stmp-int-hdrs else \ : This line works around a 'make' bug in BSDI 1.1.; \ FIXPROTO_DEFINES="$(FIXPROTO_DEFINES)"; export FIXPROTO_DEFINES; \ - FIX_HEADER="build/fix-header$(build_exeext)"; export FIX_HEADER; \ - mkinstalldirs="$(mkinstalldirs)"; \ + mkinstalldirs="$(SHELL) $(srcdir)/mkinstalldirs"; \ export mkinstalldirs; \ if [ -d "$(SYSTEM_HEADER_DIR)" ]; then \ $(SHELL) ${srcdir}/fixproto include include $(SYSTEM_HEADER_DIR); \ @@ -3347,12 +2638,6 @@ stmp-fixproto: fixhdr.ready fixproto stmp-int-hdrs $(STAMP) include/fixed; \ fi $(STAMP) stmp-fixproto - -# We can't run fixproto (it's being built for a different host), but we still -# need to install it so that the user can run it when the compiler is -# installed. -stmp-install-fixproto: fixproto - $(STAMP) $@ # # Remake the info files. @@ -3366,43 +2651,26 @@ info: $(INFOFILES) lang.info @GENINSRC@ srcinfo lang.srcinfo srcinfo: $(INFOFILES) -cp -p $^ $(srcdir)/doc -TEXI_CPP_FILES = cpp.texi fdl.texi cppenv.texi cppopts.texi \ - gcc-common.texi gcc-vers.texi - -TEXI_GCC_FILES = gcc.texi gcc-common.texi gcc-vers.texi frontends.texi \ - standards.texi invoke.texi extend.texi md.texi objc.texi \ - gcov.texi trouble.texi bugreport.texi service.texi \ - contribute.texi compat.texi funding.texi gnu.texi gpl.texi \ - fdl.texi contrib.texi cppenv.texi cppopts.texi \ - implement-c.texi - -TEXI_GCCINT_FILES = gccint.texi gcc-common.texi gcc-vers.texi \ - contribute.texi makefile.texi configterms.texi options.texi \ - portability.texi interface.texi passes.texi c-tree.texi \ - rtl.texi md.texi tm.texi hostconfig.texi fragments.texi \ - configfiles.texi collect2.texi headerdirs.texi funding.texi \ - gnu.texi gpl.texi fdl.texi contrib.texi languages.texi \ - sourcebuild.texi gty.texi libgcc.texi cfg.texi tree-ssa.texi \ - loop.texi - -TEXI_GCCINSTALL_FILES = install.texi install-old.texi fdl.texi \ - gcc-common.texi gcc-vers.texi - -TEXI_CPPINT_FILES = cppinternals.texi gcc-common.texi gcc-vers.texi - -# gcc-vers.texi is generated from the version files. -gcc-vers.texi: $(BASEVER) $(DEVPHASE) - (echo "@set version-GCC $(BASEVER_c)"; \ - if [ "$(DEVPHASE_c)" = "experimental" ]; \ - then echo "@set DEVELOPMENT"; \ - else echo "@clear DEVELOPMENT"; \ - fi) > $@T - echo "@set srcdir $(srcdir)" >> $@T - mv -f $@T $@ - - -# The *.1, *.7, *.info, *.dvi, and *.pdf files are being generated from implicit -# patterns. To use them, put each of the specific targets with its +TEXI_CPP_FILES = cpp.texi fdl.texi cppenv.texi cppopts.texi + +TEXI_GCC_FILES = gcc.texi gcc-common.texi frontends.texi standards.texi \ + invoke.texi extend.texi md.texi objc.texi gcov.texi trouble.texi \ + bugreport.texi service.texi contribute.texi compat.texi funding.texi \ + gnu.texi gpl.texi fdl.texi contrib.texi cppenv.texi cppopts.texi + +TEXI_GCCINT_FILES = gccint.texi gcc-common.texi contribute.texi makefile.texi \ + configterms.texi portability.texi interface.texi passes.texi \ + c-tree.texi rtl.texi md.texi tm.texi hostconfig.texi fragments.texi \ + configfiles.texi collect2.texi headerdirs.texi funding.texi gnu.texi \ + gpl.texi fdl.texi contrib.texi languages.texi sourcebuild.texi \ + gty.texi libgcc.texi + +TEXI_GCCINSTALL_FILES = install.texi install-old.texi fdl.texi + +TEXI_CPPINT_FILES = cppinternals.texi + +# The *.1, *.7, *.info, and *.dvi files are being generated from implicit +# patterns. To use them, put each of the specific target with with their # specific dependencies but no build commands. doc/cpp.info: $(TEXI_CPP_FILES) @@ -3412,15 +2680,15 @@ doc/cppinternals.info: $(TEXI_CPPINT_FILES) doc/%.info: %.texi if [ x$(BUILD_INFO) = xinfo ]; then \ - $(MAKEINFO) $(MAKEINFOFLAGS) -I . -I $(gcc_docdir) \ - -I $(gcc_docdir)/include -o $@ $<; \ + $(MAKEINFO) $(MAKEINFOFLAGS) -I $(docdir) \ + -I $(docdir)/include -o $@ $<; \ fi # Duplicate entry to handle renaming of gccinstall.info doc/gccinstall.info: $(TEXI_GCCINSTALL_FILES) if [ x$(BUILD_INFO) = xinfo ]; then \ - $(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \ - -I $(gcc_docdir)/include -o $@ $<; \ + $(MAKEINFO) $(MAKEINFOFLAGS) -I $(docdir) \ + -I $(docdir)/include -o $@ $<; \ fi doc/cpp.dvi: $(TEXI_CPP_FILES) @@ -3428,65 +2696,19 @@ doc/gcc.dvi: $(TEXI_GCC_FILES) doc/gccint.dvi: $(TEXI_GCCINT_FILES) doc/cppinternals.dvi: $(TEXI_CPPINT_FILES) -doc/cpp.pdf: $(TEXI_CPP_FILES) -doc/gcc.pdf: $(TEXI_GCC_FILES) -doc/gccint.pdf: $(TEXI_GCCINT_FILES) -doc/cppinternals.pdf: $(TEXI_CPPINT_FILES) - -$(build_htmldir)/cpp/index.html: $(TEXI_CPP_FILES) -$(build_htmldir)/gcc/index.html: $(TEXI_GCC_FILES) -$(build_htmldir)/gccint/index.html: $(TEXI_GCCINT_FILES) -$(build_htmldir)/cppinternals/index.html: $(TEXI_CPPINT_FILES) - dvi:: doc/gcc.dvi doc/gccint.dvi doc/gccinstall.dvi doc/cpp.dvi \ - doc/cppinternals.dvi lang.dvi + doc/cppinternals.dvi doc/%.dvi: %.texi - $(TEXI2DVI) -I . -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $< + $(TEXI2DVI) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $< # Duplicate entry to handle renaming of gccinstall.dvi doc/gccinstall.dvi: $(TEXI_GCCINSTALL_FILES) - $(TEXI2DVI) -I . -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $< - -pdf:: doc/gcc.pdf doc/gccint.pdf doc/gccinstall.pdf doc/cpp.pdf \ - doc/cppinternals.pdf lang.pdf - -doc/%.pdf: %.texi - $(TEXI2PDF) -I . -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $< - -# Duplicate entry to handle renaming of gccinstall.pdf -doc/gccinstall.pdf: $(TEXI_GCCINSTALL_FILES) - $(TEXI2PDF) -I . -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $< - -# List the directories or single hmtl files which are installed by -# install-html. The lang.html file triggers language fragments to build -# html documentation. Installing language fragment documentation is not -# yet supported. -HTMLS_INSTALL=$(build_htmldir)/cpp $(build_htmldir)/gcc \ - $(build_htmldir)/gccinstall $(build_htmldir)/gccint \ - $(build_htmldir)/cppinternals - -# List the html file targets. -HTMLS_BUILD=$(build_htmldir)/cpp/index.html $(build_htmldir)/gcc/index.html \ - $(build_htmldir)/gccinstall/index.html $(build_htmldir)/gccint/index.html \ - $(build_htmldir)/cppinternals/index.html lang.html - -html:: $(HTMLS_BUILD) - -$(build_htmldir)/%/index.html: %.texi - $(mkinstalldirs) $(@D) - rm -f $(@D)/* - $(TEXI2HTML) -I $(abs_docdir) -I $(abs_docdir)/include -o $(@D) $< - -# Duplicate entry to handle renaming of gccinstall -$(build_htmldir)/gccinstall/index.html: $(TEXI_GCCINSTALL_FILES) - $(mkinstalldirs) $(@D) - echo rm -f $(@D)/* - $(TEXI2HTML) -I $(abs_docdir) -I $(abs_docdir)/include -o $(@D) $< + $(TEXI2DVI) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $< MANFILES = doc/gcov.1 doc/cpp.1 doc/gcc.1 doc/gfdl.7 doc/gpl.7 doc/fsf-funding.7 -generated-manpages: man +generated-manpages: man man: $(MANFILES) lang.man @GENINSRC@ srcman lang.srcman @@ -3513,7 +2735,7 @@ doc/%.7: %.pod cpp.pod: cpp.texi cppenv.texi cppopts.texi # These next rules exist because the output name is not the same as -# the input name, so our implicit %.pod rule will not work. +# the input name, so our implict %.pod rule will not work. gcc.pod: invoke.texi cppenv.texi cppopts.texi $(STAMP) $@ @@ -3526,18 +2748,6 @@ fsf-funding.pod: funding.texi -$(TEXI2POD) $< > $@ # -# clean-target removes all files made by compilation. -# This can be added to over time. - -clean-target: clean-target-libgcc - -clean-target-libgcc: - test ! -d libgcc || \ - (cd libgcc && find . -type d -print) | \ - while read d; do rm -f $$d/libgcc.a || : ; done - test ! -d libgcc || rm -r libgcc - test ! -f stmp-dirs || rm stmp-dirs - # Deletion of files made during compilation. # There are four levels of this: # `mostlyclean', `clean', `distclean' and `maintainer-clean'. @@ -3552,12 +2762,13 @@ clean-target-libgcc: # (less duplicated code). mostlyclean: lang.mostlyclean - -rm -f $(STAGECOPYSTUFF) $(STAGEMOVESTUFF) + -rm -f $(STAGESTUFF) -rm -f *$(coverageexts) -rm -rf libgcc -# Delete build programs - -rm -f build/* - -rm -f mddeps.mk +# Delete the temporary source copies for cross compilation. + -rm -f $(BUILD_PREFIX_1)rtl.c $(BUILD_PREFIX_1)print-rtl.c + -rm -f $(BUILD_PREFIX_1)bitmap.c $(BUILD_PREFIX_1)errors.c + -rm -f $(BUILD_PREFIX_1)ggc-none.c print-rtl1.c # Delete the temp files made in the course of building libgcc.a. -rm -f xlimits.h # Delete other built files. @@ -3572,8 +2783,11 @@ mostlyclean: lang.mostlyclean -rm -f specs $(SPECS) SYSCALLS.c.X SYSCALLS.c -rm -f collect collect2 mips-tfile mips-tdump # Delete files generated for fixproto - -rm -rf $(build_exeext) xsys-protos.h deduced.h tmp-deduced.h \ + -rm -rf fix-header$(build_exeext) xsys-protos.h deduced.h tmp-deduced.h \ gen-protos$(build_exeext) fixproto.list fixtmp.* fixhdr.ready +# Delete files generated for fixincl + -rm -rf fixincl fixinc.sh specs.ready + (cd fixinc && $(MAKE) clean) # Delete unwanted output files from TeX. -rm -f *.toc *.log *.vr *.fn *.cp *.tp *.ky *.pg -rm -f */*.toc */*.log */*.vr */*.fn */*.cp */*.tp */*.ky */*.pg @@ -3586,8 +2800,6 @@ mostlyclean: lang.mostlyclean # Delete files generated by gengtype.c -rm -f gtype-* -rm -f gt-* -# Delete genchecksum outputs - -rm -f *-checksum.c # Delete all files made by compilation # that don't exist in the distribution. @@ -3596,11 +2808,9 @@ clean: mostlyclean lang.clean -rm -f libgcc_s* -rm -f libunwind* -rm -f config.h tconfig.h bconfig.h tm_p.h tm.h - -rm -f options.c options.h optionlist -rm -f cs-* -rm -rf libgcc -rm -f doc/*.dvi - -rm -f doc/*.pdf # Delete the include directory. -rm -rf include # Delete files used by the "multilib" facility (including libgcc subdirs). @@ -3626,7 +2836,7 @@ distclean: clean lang.distclean -rm -f Makefile *.oaux -rm -f gthr-default.h -rm -f */stage1 */stage2 */stage3 */stage4 */include */stageprofile */stagefeedback - -rm -f TAGS */TAGS + -rm -f c-parse.y c-parse.c c-parse.output TAGS */TAGS -rm -f *.asm -rm -f site.exp site.bak testsuite/site.exp testsuite/site.bak -rm -f testsuite/*.log testsuite/*.sum @@ -3634,11 +2844,12 @@ distclean: clean lang.distclean -cd testsuite && rm -f *.out *.gcov *$(coverageexts) -rm -rf ${QMTEST_DIR} stamp-qmtest -rm -f cxxmain.c - -rm -f mklibgcc gccbug .gdbinit configargs.h + -rm -f mklibgcc mkheaders gccbug .gdbinit configargs.h -rm -f gcov.pod + -rm -f fixinc/Makefile # Delete po/*.gmo only if we are not building in the source directory. -if [ ! -f po/exgettext ]; then rm -f po/*.gmo; fi - -rmdir ada cp f java objc intl po testsuite 2>/dev/null + -rmdir ada cp f java objc fixinc intl po testsuite 2>/dev/null # Get rid of every file that's generated from some other file, except for `configure'. # Most of these files ARE PRESENT in the GCC distribution. @@ -3646,9 +2857,10 @@ maintainer-clean: @echo 'This command is intended for maintainers to use; it' @echo 'deletes files that may need special tools to rebuild.' $(MAKE) lang.maintainer-clean distclean + -rm -f $(srcdir)/c-parse.y $(srcdir)/c-parse.c -rm -f cpp.??s cpp.*aux -rm -f gcc.??s gcc.*aux - -rm -f $(gcc_docdir)/*.info $(gcc_docdir)/*.1 $(gcc_docdir)/*.7 $(gcc_docdir)/*.dvi $(gcc_docdir)/*.pdf + -rm -f $(docdir)/*.info $(docdir)/*.1 $(docdir)/*.7 $(docdir)/*.dvi # # Entry points `install' and `uninstall'. # Also use `install-collect2' to install collect2 when the config files don't. @@ -3658,10 +2870,10 @@ maintainer-clean: # broken is small. install: install-common $(INSTALL_HEADERS) $(INSTALL_LIBGCC) \ install-cpp install-man install-info install-@POSUB@ \ - install-driver + lang.install-normal install-driver # Handle cpp installation. -install-cpp: installdirs cpp$(exeext) +install-cpp: cpp$(exeext) -rm -f $(DESTDIR)$(bindir)/$(CPP_INSTALL_NAME)$(exeext) -$(INSTALL_PROGRAM) -m 755 cpp$(exeext) $(DESTDIR)$(bindir)/$(CPP_INSTALL_NAME)$(exeext) -if [ x$(cpp_install_dir) != x ]; then \ @@ -3672,14 +2884,14 @@ install-cpp: installdirs cpp$(exeext) # Create the installation directories. # $(libdir)/gcc/include isn't currently searched by cpp. installdirs: - $(mkinstalldirs) $(DESTDIR)$(libsubdir) - $(mkinstalldirs) $(DESTDIR)$(libexecsubdir) - $(mkinstalldirs) $(DESTDIR)$(bindir) - $(mkinstalldirs) $(DESTDIR)$(includedir) - $(mkinstalldirs) $(DESTDIR)$(infodir) - $(mkinstalldirs) $(DESTDIR)$(slibdir) - $(mkinstalldirs) $(DESTDIR)$(man1dir) - $(mkinstalldirs) $(DESTDIR)$(man7dir) + $(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(libsubdir) + $(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(libexecsubdir) + $(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir) + $(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(includedir) + $(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(infodir) + $(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(slibdir) + $(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(man1dir) + $(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(man7dir) # Install the compiler executables built during cross compilation. install-common: native $(EXTRA_PARTS) lang.install-common installdirs @@ -3690,7 +2902,7 @@ install-common: native $(EXTRA_PARTS) lang.install-common installdirs else true; \ fi; \ done - for file in $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(COLLECT2) ..; do \ + for file in $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(USE_COLLECT2) ..; do \ if [ x"$$file" != x.. ]; then \ rm -f $(DESTDIR)$(libexecsubdir)/$$file; \ $(INSTALL_PROGRAM) $$file $(DESTDIR)$(libexecsubdir)/$$file; \ @@ -3703,11 +2915,12 @@ install-common: native $(EXTRA_PARTS) lang.install-common installdirs chmod a-x $(DESTDIR)$(libsubdir)/$$file; \ else true; fi; \ done -# We no longer install the specs file because its presence makes the -# driver slower, and because people who need it can recreate it by -# using -dumpspecs. We remove any old version because it would -# otherwise override the specs built into the driver. - rm -f $(DESTDIR)$(libsubdir)/specs +# Don't mess with specs if it doesn't exist yet. + -if [ -f specs ] ; then \ + rm -f $(DESTDIR)$(libsubdir)/specs; \ + $(INSTALL_DATA) $(SPECS) $(DESTDIR)$(libsubdir)/specs; \ + chmod a-x $(DESTDIR)$(libsubdir)/specs; \ + fi # Install protoize if it was compiled. -if [ -f protoize$(exeext) ]; then \ rm -f $(DESTDIR)$(bindir)/$(PROTOIZE_INSTALL_NAME)$(exeext); \ @@ -3726,15 +2939,15 @@ install-common: native $(EXTRA_PARTS) lang.install-common installdirs fi $(INSTALL_SCRIPT) gccbug $(DESTDIR)$(bindir)/$(GCCBUG_INSTALL_NAME) -# Install the driver program as $(target_noncanonical)-gcc, +# Install the driver program as $(target_noncanonical)-gcc, # $(target_noncanonical)-gcc-$(version) # and also as either gcc (if native) or $(gcc_tooldir)/bin/gcc. install-driver: installdirs xgcc$(exeext) -rm -f $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext) -$(INSTALL_PROGRAM) xgcc$(exeext) $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext) - -rm -f $(DESTDIR)$(bindir)/$(target_noncanonical)-gcc-$(version)$(exeext) + -rm -f $(DESTDIR)$(bindir)/$(target_noncanonical)-gcc-$(version) -( cd $(DESTDIR)$(bindir) && \ - $(LN) $(GCC_INSTALL_NAME)$(exeext) $(target_noncanonical)-gcc-$(version)$(exeext) ) + $(LN) $(GCC_INSTALL_NAME)$(exeext) $(target_noncanonical)-gcc-$(version) ) -if [ -f gcc-cross$(exeext) ] ; then \ if [ -d $(DESTDIR)$(gcc_tooldir)/bin/. ] ; then \ rm -f $(DESTDIR)$(gcc_tooldir)/bin/gcc$(exeext); \ @@ -3755,8 +2968,7 @@ install-info:: doc installdirs \ $(DESTDIR)$(infodir)/gcc.info \ $(DESTDIR)$(infodir)/cppinternals.info \ $(DESTDIR)$(infodir)/gccinstall.info \ - $(DESTDIR)$(infodir)/gccint.info \ - lang.install-info + $(DESTDIR)$(infodir)/gccint.info $(DESTDIR)$(infodir)/%.info: doc/%.info installdirs rm -f $@ @@ -3773,27 +2985,8 @@ $(DESTDIR)$(infodir)/%.info: doc/%.info installdirs else true; fi; \ else true; fi; -html__strip_dir = `echo $$p | sed -e 's|^.*/||'`; - -install-html: $(HTMLS_BUILD) - @$(NORMAL_INSTALL) - test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)" - @list='$(HTMLS_INSTALL)'; for p in $$list; do \ - if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \ - f=$(html__strip_dir) \ - if test -d "$$d$$p"; then \ - echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \ - $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ - echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \ - $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \ - else \ - echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \ - $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \ - fi; \ - done - # Install the man pages. -install-man: lang.install-man \ +install-man: installdirs lang.install-man \ $(DESTDIR)$(man1dir)/$(GCC_INSTALL_NAME)$(man1ext) \ $(DESTDIR)$(man1dir)/$(CPP_INSTALL_NAME)$(man1ext) \ $(DESTDIR)$(man1dir)/$(GCOV_INSTALL_NAME)$(man1ext) \ @@ -3801,24 +2994,24 @@ install-man: lang.install-man \ $(DESTDIR)$(man7dir)/gfdl$(man7ext) \ $(DESTDIR)$(man7dir)/gpl$(man7ext) -$(DESTDIR)$(man7dir)/%$(man7ext): doc/%.7 installdirs +$(DESTDIR)$(man7dir)/%$(man7ext): doc/%.7 -rm -f $@ -$(INSTALL_DATA) $< $@ -chmod a-x $@ -$(DESTDIR)$(man1dir)/$(GCC_INSTALL_NAME)$(man1ext): doc/gcc.1 installdirs +$(DESTDIR)$(man1dir)/$(GCC_INSTALL_NAME)$(man1ext): doc/gcc.1 -rm -f $@ - -$(INSTALL_DATA) $< $@ + -$(INSTALL_DATA) $< $@ -chmod a-x $@ -$(DESTDIR)$(man1dir)/$(CPP_INSTALL_NAME)$(man1ext): doc/cpp.1 installdirs +$(DESTDIR)$(man1dir)/$(CPP_INSTALL_NAME)$(man1ext): doc/cpp.1 -rm -f $@ - -$(INSTALL_DATA) $< $@ + -$(INSTALL_DATA) $< $@ -chmod a-x $@ -$(DESTDIR)$(man1dir)/$(GCOV_INSTALL_NAME)$(man1ext): doc/gcov.1 installdirs +$(DESTDIR)$(man1dir)/$(GCOV_INSTALL_NAME)$(man1ext): doc/gcov.1 -rm -f $@ - -$(INSTALL_DATA) $< $@ + -$(INSTALL_DATA) $< $@ -chmod a-x $@ # Install the library. @@ -3827,7 +3020,6 @@ install-libgcc: libgcc.mk libgcc.a libgcov.a installdirs CFLAGS="$(CFLAGS) $(WARN_CFLAGS)" \ CONFIG_H="$(TCONFIG_H)" \ MAKEOVERRIDES= \ - mkinstalldirs='$(mkinstalldirs)' \ -f libgcc.mk install # Install multiple versions of libgcc.a, libgcov.a. @@ -3836,7 +3028,6 @@ install-multilib: stmp-multilib installdirs CFLAGS="$(CFLAGS) $(WARN_CFLAGS)" \ CONFIG_H="$(CONFIG_H)" \ MAKEOVERRIDES= \ - mkinstalldirs='$(mkinstalldirs)' \ -f libgcc.mk install # Install all the header files built in the include subdirectory. @@ -3862,13 +3053,6 @@ install-include-dir: installdirs mkdir $(DESTDIR)$(libsubdir)/include -chmod a+rx $(DESTDIR)$(libsubdir)/include -# Create or recreate the install-tools include file directory. -itoolsdir = $(libexecsubdir)/install-tools -itoolsdatadir = $(libsubdir)/install-tools -install-itoolsdirs: installdirs - $(mkinstalldirs) $(DESTDIR)$(itoolsdatadir)/include - $(mkinstalldirs) $(DESTDIR)$(itoolsdir) - # Install the include directory using tar. install-headers-tar: stmp-int-hdrs $(STMP_FIXPROTO) install-include-dir # We use `pwd`/include instead of just include to problems with CDPATH @@ -3891,38 +3075,37 @@ install-headers-cpio: stmp-int-hdrs $(STMP_FIXPROTO) install-include-dir install-headers-cp: stmp-int-hdrs $(STMP_FIXPROTO) install-include-dir cp -p -r include $(DESTDIR)$(libsubdir) -# Targets without dependencies, for use in prev-gcc during bootstrap. -real-install-headers-tar: - (cd `${PWD_COMMAND}`/include ; \ - tar -cf - .; exit 0) | (cd $(DESTDIR)$(libsubdir)/include; tar xpf - ) - -real-install-headers-cpio: - cd `${PWD_COMMAND}`/include ; \ - find . -print | cpio -pdum $(DESTDIR)$(libsubdir)/include - -real-install-headers-cp: - cp -p -r include $(DESTDIR)$(libsubdir) - -# Install supporting files for fixincludes to be run later. -install-mkheaders: stmp-int-hdrs $(STMP_FIXPROTO) install-itoolsdirs \ - macro_list xlimits.h +itoolsdir = $(libexecsubdir)/install-tools +itoolsdatadir = $(libsubdir)/install-tools +# Don't install the headers. Instead, install appropriate scripts +# and supporting files for fixincludes to be run later. +install-mkheaders: stmp-int-hdrs $(STMP_FIXPROTO) install-include-dir \ + mkheaders xlimits.h + -rm -rf $(DESTDIR)$(itoolsdir) $(DESTDIR)$(itoolsdatadir) + $(SHELL) $(srcdir)/mkinstalldirs $(DESTDIR)$(itoolsdatadir)/include + $(SHELL) $(srcdir)/mkinstalldirs $(DESTDIR)$(itoolsdir) for file in $(USER_H); do \ realfile=`echo $$file | sed -e 's|.*/\([^/]*\)$$|\1|'`; \ $(INSTALL_DATA) $$file \ $(DESTDIR)$(itoolsdatadir)/include/$$realfile ; \ done $(INSTALL_DATA) xlimits.h $(DESTDIR)$(itoolsdatadir)/include/limits.h - $(INSTALL_DATA) $(UNWIND_H) $(DESTDIR)$(itoolsdatadir)/include/unwind.h - $(INSTALL_DATA) $(srcdir)/gsyslimits.h \ - $(DESTDIR)$(itoolsdatadir)/gsyslimits.h - $(INSTALL_DATA) macro_list $(DESTDIR)$(itoolsdatadir)/macro_list + if [ x$(STMP_FIXINC) != x ] ; then \ + $(INSTALL_DATA) $(srcdir)/README-fixinc \ + $(DESTDIR)$(itoolsdatadir)/include/README ; \ + $(INSTALL_SCRIPT) fixinc.sh $(DESTDIR)$(itoolsdir)/fixinc.sh ; \ + $(INSTALL_PROGRAM) fixinc/fixincl $(DESTDIR)$(itoolsdir)/fixincl ; \ + $(INSTALL_DATA) $(srcdir)/gsyslimits.h \ + $(DESTDIR)$(itoolsdatadir)/gsyslimits.h ; \ + else :; fi if [ x$(STMP_FIXPROTO) != x ] ; then \ - $(INSTALL_SCRIPT) $(mkinstalldirs) \ + $(INSTALL_SCRIPT) $(srcdir)/mkinstalldirs \ $(DESTDIR)$(itoolsdir)/mkinstalldirs ; \ $(INSTALL_SCRIPT) $(srcdir)/fixproto $(DESTDIR)$(itoolsdir)/fixproto ; \ - $(INSTALL_PROGRAM) build/fix-header$(build_exeext) \ + $(INSTALL_PROGRAM) fix-header$(build_exeext) \ $(DESTDIR)$(itoolsdir)/fix-header$(build_exeext) ; \ else :; fi + $(INSTALL_SCRIPT) mkheaders $(DESTDIR)$(itoolsdir)/mkheaders echo 'SYSTEM_HEADER_DIR="'"$(SYSTEM_HEADER_DIR)"'"' \ > $(DESTDIR)$(itoolsdatadir)/mkheaders.conf echo 'OTHER_FIXINCLUDES_DIRS="$(OTHER_FIXINCLUDES_DIRS)"' \ @@ -3978,12 +3161,9 @@ site.exp: ./config.status Makefile @echo "set build_triplet $(build)" >> ./tmp0 @echo "set target_triplet $(target)" >> ./tmp0 @echo "set target_alias $(target_noncanonical)" >> ./tmp0 - @echo "set libiconv \"$(LIBICONV)\"" >> ./tmp0 # CFLAGS is set even though it's empty to show we reserve the right to set it. @echo "set CFLAGS \"\"" >> ./tmp0 @echo "set CXXFLAGS \"\"" >> ./tmp0 - @echo "set HOSTCC \"$(CC)\"" >> ./tmp0 - @echo "set HOSTCFLAGS \"$(CFLAGS)\"" >> ./tmp0 @echo "set TESTING_IN_BUILD_TREE 1" >> ./tmp0 @echo "set HAVE_LIBSTDCXX_V3 1" >> ./tmp0 # If newlib has been configured, we need to pass -B to gcc so it can find @@ -4049,23 +3229,17 @@ $(lang_checks_parallel): site.exp TESTSUITEDIR = testsuite $(TESTSUITEDIR)/site.exp: site.exp - -test -d $(TESTSUITEDIR) || mkdir $(TESTSUITEDIR) + test -d $(TESTSUITEDIR) || mkdir $(TESTSUITEDIR) -rm -f $@ sed '/set tmpdir/ s|testsuite|$(TESTSUITEDIR)|' < site.exp > $@ -$(lang_checks): check-% : site.exp - -test -d $(TESTSUITEDIR) || mkdir $(TESTSUITEDIR) - test -d $(TESTSUITEDIR)/$* || mkdir $(TESTSUITEDIR)/$* +$(lang_checks): check-% : $(TESTSUITEDIR)/site.exp -(rootme=`${PWD_COMMAND}`; export rootme; \ srcdir=`cd ${srcdir}; ${PWD_COMMAND}` ; export srcdir ; \ - cd $(TESTSUITEDIR)/$*; \ - rm -f tmp-site.exp; \ - sed '/set tmpdir/ s|testsuite|$(TESTSUITEDIR)/$*|' \ - < ../../site.exp > tmp-site.exp; \ - $(SHELL) $${srcdir}/../move-if-change tmp-site.exp site.exp; \ + cd $(TESTSUITEDIR); \ EXPECT=${EXPECT} ; export EXPECT ; \ if [ -f $${rootme}/../expect/expect ] ; then \ - TCL_LIBRARY=`cd .. ; cd $${srcdir}/../tcl/library ; ${PWD_COMMAND}` ; \ + TCL_LIBRARY=`cd .. ; cd ${srcdir}/../tcl/library ; ${PWD_COMMAND}` ; \ export TCL_LIBRARY ; fi ; \ $(RUNTEST) --tool $* $(RUNTESTFLAGS)) @@ -4075,7 +3249,7 @@ check-consistency: testsuite/site.exp cd testsuite; \ EXPECT=${EXPECT} ; export EXPECT ; \ if [ -f $${rootme}/../expect/expect ] ; then \ - TCL_LIBRARY=`cd .. ; cd $${srcdir}/../tcl/library ; ${PWD_COMMAND}` ; \ + TCL_LIBRARY=`cd .. ; cd ${srcdir}/../tcl/library ; ${PWD_COMMAND}` ; \ export TCL_LIBRARY ; fi ; \ $(RUNTEST) --tool consistency $(RUNTESTFLAGS) @@ -4134,8 +3308,8 @@ qmtest-gui: ${QMTEST_DIR}/context # Run Paranoia on real.c. paranoia.o: $(srcdir)/../contrib/paranoia.cc $(CONFIG_H) $(SYSTEM_H) \ - $(REAL_H) $(TREE_H) - g++ -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION) + real.h $(TREE_H) + g++ -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) paranoia: paranoia.o real.o $(LIBIBERTY) g++ -o $@ paranoia.o real.o $(LIBIBERTY) @@ -4151,7 +3325,11 @@ TAGS: lang.tags incs="$$incs --include $$dir/TAGS.sub"; \ fi; \ done; \ - etags -o TAGS.sub *.y *.h *.c; \ + mkdir tmp-tags; \ + mv -f c-parse.[ch] tmp-tags; \ + etags -o TAGS.sub *.y *.h *.c; \ + mv tmp-tags/* .; \ + rmdir tmp-tags; \ etags --include TAGS.sub $$incs) # ------------------------------------------------------ @@ -4159,7 +3337,7 @@ TAGS: lang.tags # ------------------------------------------------------ # A list of files to be destroyed during "lean" builds. -VOL_FILES=`echo $(BACKEND) $(OBJS) $(C_OBJS) *.c *.h gen*` +VOL_FILES=`echo $(BACKEND) $(OBJS) $(C_OBJS) $(LIBCPP_OBJS) *.c *.h gen*` # Flags to pass to stage2 and later recursive makes. Note that the # WARN_CFLAGS setting can't be to the expansion of GCC_WARN_CFLAGS in @@ -4180,27 +3358,26 @@ POSTSTAGE1_FLAGS_TO_PASS = \ STAGE2_FLAGS_TO_PASS = \ CFLAGS="$(BOOT_CFLAGS)" \ - WERROR="$(WERROR_FLAGS)" \ + WERROR="@WERROR@" \ STAGEPROFILE_FLAGS_TO_PASS = \ - CFLAGS="$(BOOT_CFLAGS) -fprofile-generate" + CFLAGS="$(BOOT_CFLAGS) -fprofile-generate" # Files never linked into the final executable produces warnings about missing # profile. STAGEFEEDBACK_FLAGS_TO_PASS = \ - CFLAGS="$(BOOT_CFLAGS) -fprofile-use -freorder-blocks-and-partition" + CFLAGS="$(BOOT_CFLAGS) -fprofile-use" # Only build the C compiler for stage1, because that is the only one that # we can guarantee will build with the native compiler, and also it is the # only thing useful for building stage2. STAGE1_CFLAGS (via CFLAGS), # MAKEINFO and MAKEINFOFLAGS are explicitly passed here to make them # overrideable (for a bootstrap build stage1 also builds gcc.info). -# The stage1 compiler is always built with checking enabled. stage1_build: $(MAKE) CC="$(CC)" libdir=$(libdir) LANGUAGES="$(BOOT_LANGUAGES)" \ - CFLAGS="$(STAGE1_CFLAGS) $(STAGE1_CHECKING_CFLAGS)" \ - MAKEINFO="$(MAKEINFO)" MAKEINFOFLAGS="$(MAKEINFOFLAGS)" \ - COVERAGE_FLAGS= OBJS-onestep="$(OBJS)" + CFLAGS="$(STAGE1_CFLAGS)" MAKEINFO="$(MAKEINFO)" \ + MAKEINFOFLAGS="$(MAKEINFOFLAGS)" COVERAGE_FLAGS= \ + OBJS-onestep="$(OBJS)" $(STAMP) stage1_build echo stage1_build > stage_last @@ -4304,7 +3481,7 @@ bootstrap4 bootstrap4-lean: stage4_build unstage1 unstage2 unstage3 unstage4 unstageprofile unstagefeedback: -set -vx; stage=`echo $@ | sed -e 's/un//'`; \ rm -f $$stage/as$(exeext); \ - rm -f $$stage/nm$(exeext); \ + rm -f $$stage/ld$(exeext); \ rm -f $$stage/collect-ld$(exeext); \ if test -d $$stage; then \ mv $$stage/specs $(SPECS) 2>/dev/null || :; \ @@ -4359,19 +3536,12 @@ bubblestrap: $(MAKE) $(REMAKEFLAGS) stage4_build || exit 1; \ fi -BOOTSTRAPPING := $(shell if test -f ../stage_last; then echo yes; else echo no; fi) -ifeq ($(BOOTSTRAPPING),yes) -# Provide quickstrap as a target that people can type into the gcc directory, -# and that fails if you're not into it. -quickstrap: all -else quickstrap: if test -f stage_last ; then \ LAST=`cat stage_last`; rm $$LAST; $(MAKE) $(REMAKEFLAGS) $$LAST; \ else \ $(MAKE) $(REMAKEFLAGS) stage1_build; \ fi -endif cleanstrap: -$(MAKE) clean @@ -4403,38 +3573,24 @@ fastcompare fastcompare3 fastcompare4 fastcompare-lean fastcompare3-lean fastcom gnucompare gnucompare3 gnucompare4 gnucompare-lean gnucompare3-lean gnucompare4-lean: force -rm -f .bad_compare case "$@" in *compare | *compare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^[a-z]*compare\([0-9][0-9]*\).*,\1,'` ;; esac; \ - for dir in . $(SUBDIRS) libgcc; do \ + for dir in . $(SUBDIRS); do \ if [ "`echo $$dir/*$(objext)`" != "$$dir/*$(objext)" ] ; then \ for file in $$dir/*$(objext); do \ case "$@" in \ slowcompare* ) \ - if tail -c +1 </dev/null >/dev/null 2>&1; then \ - skip16='-c +17'; \ - else \ - skip16='+17c'; \ - fi; \ - tail $$skip16 ./$$file > tmp-foo1; \ - tail $$skip16 stage$$stage/$$file > tmp-foo2; \ - cmp tmp-foo1 tmp-foo2 > /dev/null 2>&1; \ - cmpret=$$?; \ + tail +16c ./$$file > tmp-foo1; \ + tail +16c stage$$stage/$$file > tmp-foo2 \ + && (cmp tmp-foo1 tmp-foo2 > /dev/null 2>&1 || echo $$file differs >> .bad_compare) || true; \ ;; \ fastcompare* ) \ cmp $$file stage$$stage/$$file 16 16 > /dev/null 2>&1; \ - cmpret=$$?; \ + test $$? -eq 1 && echo $$file differs >> .bad_compare || true; \ ;; \ gnucompare* ) \ cmp --ignore-initial=16 $$file stage$$stage/$$file > /dev/null 2>&1; \ - cmpret=$$?; \ + test $$? -eq 1 && echo $$file differs >> .bad_compare || true; \ ;; \ esac ; \ - if test $$cmpret -eq 1; then \ - case $$file in \ - ./cc*-checksum$(objext) | libgcc/* ) \ - echo warning: $$file differs;; \ - *) \ - echo $$file differs >> .bad_compare;; \ - esac ; \ - fi; \ done; \ else true; fi; \ done @@ -4467,19 +3623,17 @@ stage1-start: do \ if [ -d stage1/$$dir ] ; then true ; else mkdir stage1/$$dir ; fi ; \ done - -rm -f stage1/libgcc.a stage1/libgcc_eh.a stage1/libgcov.a - -rm -f stage1/libgcc_s*$(SHLIB_EXT) - -rm -f stage1/libunwind.a stage1/libunwind*$(SHLIB_EXT) # If SPECS is overridden, make sure it is `installed' as specs. -mv $(SPECS) stage1/specs - -mv $(STAGEMOVESTUFF) stage1 - -mv build/* stage1/build - -cp -p $(STAGECOPYSTUFF) stage1 + -mv $(STAGESTUFF) stage1 # Copy as/ld if they exist to stage dir, so that running xgcc from the stage # dir will work properly. -if [ -f as$(exeext) ] ; then (cd stage1 && $(LN_S) ../as$(exeext) .) ; else true ; fi -if [ -f ld$(exeext) ] ; then (cd stage1 && $(LN_S) ../ld$(exeext) .) ; else true ; fi -if [ -f collect-ld$(exeext) ] ; then (cd stage1 && $(LN_S) ../collect-ld$(exeext) .) ; else true ; fi + -rm -f stage1/libgcc.a stage1/libgcc_eh.a stage1/libgcov.a + -rm -f stage1/libgcc_s*$(SHLIB_EXT) + -rm -f stage1/libunwind.a stage1/libunwind*$(SHLIB_EXT) -cp libgcc.a stage1 -$(RANLIB_FOR_TARGET) stage1/libgcc.a -cp libgcov.a stage1 @@ -4506,19 +3660,17 @@ stage2-start: do \ if [ -d stage2/$$dir ] ; then true ; else mkdir stage2/$$dir ; fi ; \ done - -rm -f stage2/libgcc.a stage2/libgcov.a stage2/libgcc_eh.a - -rm -f stage2/libgcc_s*$(SHLIB_EXT) - -rm -f stage2/libunwind.a stage2/libunwind*$(SHLIB_EXT) # If SPECS is overridden, make sure it is `installed' as specs. -mv $(SPECS) stage2/specs - -mv $(STAGEMOVESTUFF) stage2 - -mv build/* stage2/build - -cp -p $(STAGECOPYSTUFF) stage2 + -mv $(STAGESTUFF) stage2 # Copy as/ld if they exist to stage dir, so that running xgcc from the stage # dir will work properly. -if [ -f as$(exeext) ] ; then (cd stage2 && $(LN_S) ../as$(exeext) .) ; else true ; fi -if [ -f ld$(exeext) ] ; then (cd stage2 && $(LN_S) ../ld$(exeext) .) ; else true ; fi -if [ -f collect-ld$(exeext) ] ; then (cd stage2 && $(LN_S) ../collect-ld$(exeext) .) ; else true ; fi + -rm -f stage2/libgcc.a stage2/libgcov.a stage2/libgcc_eh.a + -rm -f stage2/libgcc_s*$(SHLIB_EXT) + -rm -f stage2/libunwind.a stage2/libunwind*$(SHLIB_EXT) -cp libgcc.a stage2 -$(RANLIB_FOR_TARGET) stage2/libgcc.a -cp libgcov.a stage2 @@ -4541,19 +3693,17 @@ stage3-start: do \ if [ -d stage3/$$dir ] ; then true ; else mkdir stage3/$$dir ; fi ; \ done - -rm -f stage3/libgcc.a stage3/libgcov.a stage3/libgcc_eh.a - -rm -f stage3/libgcc_s*$(SHLIB_EXT) - -rm -f stage3/libunwind.a stage3/libunwind*$(SHLIB_EXT) # If SPECS is overridden, make sure it is `installed' as specs. -mv $(SPECS) stage3/specs - -mv $(STAGEMOVESTUFF) stage3 - -mv build/* stage3/build - -cp -p $(STAGECOPYSTUFF) stage3 + -mv $(STAGESTUFF) stage3 # Copy as/ld if they exist to stage dir, so that running xgcc from the stage # dir will work properly. -if [ -f as$(exeext) ] ; then (cd stage3 && $(LN_S) ../as$(exeext) .) ; else true ; fi -if [ -f ld$(exeext) ] ; then (cd stage3 && $(LN_S) ../ld$(exeext) .) ; else true ; fi -if [ -f collect-ld$(exeext) ] ; then (cd stage3 && $(LN_S) ../collect-ld$(exeext) .) ; else true ; fi + -rm -f stage3/libgcc.a stage3/libgcov.a stage3/libgcc_eh.a + -rm -f stage3/libgcc_s*$(SHLIB_EXT) + -rm -f stage3/libunwind.a stage3/libunwind*$(SHLIB_EXT) -cp libgcc.a stage3 -$(RANLIB_FOR_TARGET) stage3/libgcc.a -cp libgcov.a stage3 @@ -4576,19 +3726,17 @@ stage4-start: do \ if [ -d stage4/$$dir ] ; then true ; else mkdir stage4/$$dir ; fi ; \ done - -rm -f stage4/libgcc.a stage4/libgcov.a stage4/libgcc_eh.a - -rm -f stage4/libgcc_s*$(SHLIB_EXT) - -rm -f stage4/libunwind.a stage4/libunwind*$(SHLIB_EXT) # If SPECS is overridden, make sure it is `installed' as specs. -mv $(SPECS) stage4/specs - -mv $(STAGEMOVESTUFF) stage4 - -mv build/* stage4/build - -cp -p $(STAGECOPYSTUFF) stage4 + -mv $(STAGESTUFF) stage4 # Copy as/ld if they exist to stage dir, so that running xgcc from the stage # dir will work properly. -if [ -f as$(exeext) ] ; then (cd stage4 && $(LN_S) ../as$(exeext) .) ; else true ; fi -if [ -f ld$(exeext) ] ; then (cd stage4 && $(LN_S) ../ld$(exeext) .) ; else true ; fi -if [ -f collect-ld$(exeext) ] ; then (cd stage4 && $(LN_S) ../collect-ld$(exeext) .) ; else true ; fi + -rm -f stage4/libgcc.a stage4/libgcov.a stage4/libgcc_eh.a + -rm -f stage4/libgcc_s*$(SHLIB_EXT) + -rm -f stage4/libunwind.a stage4/libunwind*$(SHLIB_EXT) -cp libgcc.a stage4 -$(RANLIB_FOR_TARGET) stage4/libgcc.a -cp libgcov.a stage4 @@ -4611,17 +3759,15 @@ stageprofile-start: do \ if [ -d stageprofile/$$dir ] ; then true ; else mkdir stageprofile/$$dir ; fi ; \ done - -rm -f stageprofile/libgcc.a stageprofile/libgcov.a stageprofile/libgcc_eh.a - -rm -f stageprofile/libgcc_s*$(SHLIB_EXT) - -rm -f stageprofile/libunwind.a stageprofile/libunwind*$(SHLIB_EXT) - -mv $(STAGEMOVESTUFF) stageprofile - -mv build/* stageprofile/build - -cp -p $(STAGECOPYSTUFF) stageprofile + -mv $(STAGESTUFF) stageprofile # Copy as/ld if they exist to stage dir, so that running xgcc from the stage # dir will work properly. -if [ -f as$(exeext) ] ; then (cd stageprofile && $(LN_S) ../as$(exeext) .) ; else true ; fi -if [ -f ld$(exeext) ] ; then (cd stageprofile && $(LN_S) ../ld$(exeext) .) ; else true ; fi -if [ -f collect-ld$(exeext) ] ; then (cd stageprofile && $(LN_S) ../collect-ld$(exeext) .) ; else true ; fi + -rm -f stageprofile/libgcc.a stageprofile/libgcov.a stageprofile/libgcc_eh.a + -rm -f stageprofile/libgcc_s*$(SHLIB_EXT) + -rm -f stageprofile/libunwind.a stageprofile/libunwind*$(SHLIB_EXT) -cp libgcc.a stageprofile -$(RANLIB_FOR_TARGET) stageprofile/libgcc.a -cp libgcov.a stageprofile @@ -4644,18 +3790,16 @@ stagefeedback-start: do \ if [ -d stagefeedback/$$dir ] ; then true ; else mkdir stagefeedback/$$dir ; fi ; \ done - -rm -f stagefeedback/libgcc.a stagefeedback/libgcov.a stagefeedback/libgcc_eh.a - -rm -f stagefeedback/libgcc_s*$(SHLIB_EXT) - -rm -f stagefeedback/libunwind.a stagefeedback/libunwind*$(SHLIB_EXT) - -rm -f *.da - -mv $(STAGEMOVESTUFF) stagefeedback - -mv build/* stagefeedback/build - -cp -p $(STAGECOPYSTUFF) stagefeedback + -mv $(STAGESTUFF) stagefeedback # Copy as/ld if they exist to stage dir, so that running xgcc from the stage # dir will work properly. -if [ -f as$(exeext) ] ; then (cd stagefeedback && $(LN_S) ../as$(exeext) .) ; else true ; fi -if [ -f ld$(exeext) ] ; then (cd stagefeedback && $(LN_S) ../ld$(exeext) .) ; else true ; fi -if [ -f collect-ld$(exeext) ] ; then (cd stagefeedback && $(LN_S) ../collect-ld$(exeext) .) ; else true ; fi + -rm -f stagefeedback/libgcc.a stagefeedback/libgcov.a stagefeedback/libgcc_eh.a + -rm -f stagefeedback/libgcc_s*$(SHLIB_EXT) + -rm -f stagefeedback/libunwind.a stagefeedback/libunwind*$(SHLIB_EXT) + -rm -f *.da -for dir in fixinc po testsuite $(SUBDIRS); \ do \ rm -f $$dir/*.da ; \ @@ -4703,7 +3847,9 @@ risky-stage4: stage4 XGETTEXT = @XGETTEXT@ GMSGFMT = @GMSGFMT@ MSGMERGE = msgmerge -CATALOGS = $(patsubst %,po/%,@CATALOGS@) + +PACKAGE = @PACKAGE@ +CATALOGS = @CATALOGS@ .PHONY: build- install- build-po install-po update-po @@ -4726,20 +3872,20 @@ update-po: $(CATALOGS:.gmo=.pox) # The new .po has to be gone over by hand, so we deposit it into # build/po with a different extension. -# If build/po/gcc.pot exists, use it (it was just created), +# If build/po/$(PACKAGE).pot exists, use it (it was just created), # else use the one in srcdir. .po.pox: -test -d po || mkdir po - $(MSGMERGE) $< `if test -f po/gcc.pot; \ - then echo po/gcc.pot; \ - else echo $(srcdir)/po/gcc.pot; fi` -o $@ + $(MSGMERGE) $< `if test -f po/$(PACKAGE).pot; \ + then echo po/$(PACKAGE).pot; \ + else echo $(srcdir)/po/$(PACKAGE).pot; fi` -o $@ # This rule has to look for .gmo modules in both srcdir and # the cwd, and has to check that we actually have a catalog # for each language, in case they weren't built or included # with the distribution. install-po: - $(mkinstalldirs) $(DESTDIR)$(datadir) + $(SHELL) $(srcdir)/mkinstalldirs $(DESTDIR)$(datadir) cats="$(CATALOGS)"; for cat in $$cats; do \ lang=`basename $$cat | sed 's/\.gmo$$//'`; \ if [ -f $$cat ]; then :; \ @@ -4747,10 +3893,10 @@ install-po: else continue; \ fi; \ dir=$(localedir)/$$lang/LC_MESSAGES; \ - echo $(mkinstalldirs) $(DESTDIR)$$dir; \ - $(mkinstalldirs) $(DESTDIR)$$dir || exit 1; \ - echo $(INSTALL_DATA) $$cat $(DESTDIR)$$dir/gcc.mo; \ - $(INSTALL_DATA) $$cat $(DESTDIR)$$dir/gcc.mo; \ + echo $(SHELL) $(srcdir)/mkinstalldirs $(DESTDIR)$$dir; \ + $(SHELL) $(srcdir)/mkinstalldirs $(DESTDIR)$$dir || exit 1; \ + echo $(INSTALL_DATA) $$cat $(DESTDIR)$$dir/$(PACKAGE).mo; \ + $(INSTALL_DATA) $$cat $(DESTDIR)$$dir/$(PACKAGE).mo; \ done # Rule for regenerating the message template (gcc.pot). @@ -4760,9 +3906,9 @@ install-po: # Note that exgettext has an awk script embedded in it which requires a # fairly modern (POSIX-compliant) awk. # The .pot file is left in the build directory. -gcc.pot: po/gcc.pot -po/gcc.pot: force +$(PACKAGE).pot: po/$(PACKAGE).pot +po/$(PACKAGE).pot: force options.c -test -d po || mkdir po $(MAKE) srcextra AWK=$(AWK) $(SHELL) $(srcdir)/po/exgettext \ - $(XGETTEXT) gcc $(srcdir) + $(XGETTEXT) $(PACKAGE) $(srcdir) diff --git a/contrib/gcc/builtins.c b/contrib/gcc/builtins.c index 27f1989..2931684 100644 --- a/contrib/gcc/builtins.c +++ b/contrib/gcc/builtins.c @@ -1,6 +1,6 @@ /* Expand builtin functions. Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #include "config.h" #include "system.h" @@ -27,7 +27,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "real.h" #include "rtl.h" #include "tree.h" -#include "tree-gimple.h" #include "flags.h" #include "regs.h" #include "hard-reg-set.h" @@ -45,8 +44,17 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "tm_p.h" #include "target.h" #include "langhooks.h" -#include "basic-block.h" -#include "tree-mudflap.h" + +#define CALLED_AS_BUILT_IN(NODE) \ + (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10)) + +/* Register mappings for target machines without register windows. */ +#ifndef INCOMING_REGNO +#define INCOMING_REGNO(OUT) (OUT) +#endif +#ifndef OUTGOING_REGNO +#define OUTGOING_REGNO(IN) (IN) +#endif #ifndef PAD_VARARGS_DOWN #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN @@ -56,8 +64,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA const char *const built_in_class_names[4] = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"}; -#define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM, COND) #X, -const char * built_in_names[(int) END_BUILTINS] = +#define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM) #X, +const char *const built_in_names[(int) END_BUILTINS] = { #include "builtins.def" }; @@ -68,20 +76,22 @@ const char * built_in_names[(int) END_BUILTINS] = tree built_in_decls[(int) END_BUILTINS]; /* Declarations used when constructing the builtin implicitly in the compiler. It may be NULL_TREE when this is invalid (for instance runtime is not - required to implement the function call in all cases). */ + required to implement the function call in all cases. */ tree implicit_built_in_decls[(int) END_BUILTINS]; static int get_pointer_alignment (tree, unsigned int); +static tree c_strlen (tree, int); static const char *c_getstr (tree); static rtx c_readstr (const char *, enum machine_mode); static int target_char_cast (tree, char *); -static rtx get_memory_rtx (tree, tree); +static rtx get_memory_rtx (tree); +static tree build_string_literal (int, const char *); static int apply_args_size (void); static int apply_result_size (void); #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return) static rtx result_vector (int, rtx); #endif -static void expand_builtin_update_setjmp_buf (rtx); +static rtx expand_builtin_setjmp (tree, rtx); static void expand_builtin_prefetch (tree); static rtx expand_builtin_apply_args (void); static rtx expand_builtin_apply_args_1 (void); @@ -92,11 +102,9 @@ static rtx expand_builtin_classify_type (tree); static void expand_errno_check (tree, rtx); static rtx expand_builtin_mathfn (tree, rtx, rtx); static rtx expand_builtin_mathfn_2 (tree, rtx, rtx); -static rtx expand_builtin_mathfn_3 (tree, rtx, rtx); -static rtx expand_builtin_sincos (tree); -static rtx expand_builtin_int_roundingfn (tree, rtx, rtx); +static rtx expand_builtin_constant_p (tree, enum machine_mode); static rtx expand_builtin_args_info (tree); -static rtx expand_builtin_next_arg (void); +static rtx expand_builtin_next_arg (tree); static rtx expand_builtin_va_start (tree); static rtx expand_builtin_va_end (tree); static rtx expand_builtin_va_copy (tree); @@ -104,27 +112,27 @@ static rtx expand_builtin_memcmp (tree, tree, rtx, enum machine_mode); static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode); static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode); static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode); -static rtx expand_builtin_strcat (tree, tree, rtx, enum machine_mode); +static rtx expand_builtin_strcat (tree, rtx, enum machine_mode); static rtx expand_builtin_strncat (tree, rtx, enum machine_mode); static rtx expand_builtin_strspn (tree, rtx, enum machine_mode); static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode); static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode); -static rtx expand_builtin_mempcpy (tree, tree, rtx, enum machine_mode, int); -static rtx expand_builtin_memmove (tree, tree, rtx, enum machine_mode, tree); +static rtx expand_builtin_mempcpy (tree, rtx, enum machine_mode, int); +static rtx expand_builtin_memmove (tree, rtx, enum machine_mode); static rtx expand_builtin_bcopy (tree); -static rtx expand_builtin_strcpy (tree, tree, rtx, enum machine_mode); +static rtx expand_builtin_strcpy (tree, rtx, enum machine_mode); static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode); static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode); static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode); static rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode); static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode); -static rtx expand_builtin_memset (tree, rtx, enum machine_mode, tree); +static rtx expand_builtin_memset (tree, rtx, enum machine_mode); static rtx expand_builtin_bzero (tree); static rtx expand_builtin_strlen (tree, rtx, enum machine_mode); -static rtx expand_builtin_strstr (tree, tree, rtx, enum machine_mode); -static rtx expand_builtin_strpbrk (tree, tree, rtx, enum machine_mode); -static rtx expand_builtin_strchr (tree, tree, rtx, enum machine_mode); -static rtx expand_builtin_strrchr (tree, tree, rtx, enum machine_mode); +static rtx expand_builtin_strstr (tree, rtx, enum machine_mode); +static rtx expand_builtin_strpbrk (tree, rtx, enum machine_mode); +static rtx expand_builtin_strchr (tree, rtx, enum machine_mode); +static rtx expand_builtin_strrchr (tree, rtx, enum machine_mode); static rtx expand_builtin_alloca (tree, rtx); static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab); static rtx expand_builtin_frame_address (tree, tree); @@ -136,88 +144,27 @@ static tree stabilize_va_list (tree, int); static rtx expand_builtin_expect (tree, rtx); static tree fold_builtin_constant_p (tree); static tree fold_builtin_classify_type (tree); -static tree fold_builtin_strlen (tree); static tree fold_builtin_inf (tree, int); static tree fold_builtin_nan (tree, tree, int); static int validate_arglist (tree, ...); static bool integer_valued_real_p (tree); -static tree fold_trunc_transparent_mathfn (tree, tree); +static tree fold_trunc_transparent_mathfn (tree); static bool readonly_data_expr (tree); static rtx expand_builtin_fabs (tree, rtx, rtx); -static rtx expand_builtin_signbit (tree, rtx); -static tree fold_builtin_sqrt (tree, tree); -static tree fold_builtin_cbrt (tree, tree); -static tree fold_builtin_pow (tree, tree, tree); -static tree fold_builtin_powi (tree, tree, tree); -static tree fold_builtin_sin (tree); -static tree fold_builtin_cos (tree, tree, tree); -static tree fold_builtin_tan (tree); -static tree fold_builtin_atan (tree, tree); -static tree fold_builtin_trunc (tree, tree); -static tree fold_builtin_floor (tree, tree); -static tree fold_builtin_ceil (tree, tree); -static tree fold_builtin_round (tree, tree); -static tree fold_builtin_int_roundingfn (tree, tree); -static tree fold_builtin_bitop (tree, tree); -static tree fold_builtin_memory_op (tree, tree, bool, int); -static tree fold_builtin_strchr (tree, tree); +static rtx expand_builtin_cabs (tree, rtx); +static tree fold_builtin_cabs (tree, tree, tree); +static tree fold_builtin_trunc (tree); +static tree fold_builtin_floor (tree); +static tree fold_builtin_ceil (tree); +static tree fold_builtin_bitop (tree); +static tree fold_builtin_memcpy (tree); +static tree fold_builtin_mempcpy (tree); +static tree fold_builtin_memmove (tree); +static tree fold_builtin_strcpy (tree); +static tree fold_builtin_strncpy (tree); static tree fold_builtin_memcmp (tree); static tree fold_builtin_strcmp (tree); static tree fold_builtin_strncmp (tree); -static tree fold_builtin_signbit (tree, tree); -static tree fold_builtin_copysign (tree, tree, tree); -static tree fold_builtin_isascii (tree); -static tree fold_builtin_toascii (tree); -static tree fold_builtin_isdigit (tree); -static tree fold_builtin_fabs (tree, tree); -static tree fold_builtin_abs (tree, tree); -static tree fold_builtin_unordered_cmp (tree, tree, enum tree_code, - enum tree_code); -static tree fold_builtin_1 (tree, tree, bool); - -static tree fold_builtin_strpbrk (tree, tree); -static tree fold_builtin_strstr (tree, tree); -static tree fold_builtin_strrchr (tree, tree); -static tree fold_builtin_strcat (tree); -static tree fold_builtin_strncat (tree); -static tree fold_builtin_strspn (tree); -static tree fold_builtin_strcspn (tree); -static tree fold_builtin_sprintf (tree, int); - -static rtx expand_builtin_object_size (tree); -static rtx expand_builtin_memory_chk (tree, rtx, enum machine_mode, - enum built_in_function); -static void maybe_emit_chk_warning (tree, enum built_in_function); -static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function); -static tree fold_builtin_object_size (tree); -static tree fold_builtin_strcat_chk (tree, tree); -static tree fold_builtin_strncat_chk (tree, tree); -static tree fold_builtin_sprintf_chk (tree, enum built_in_function); -static tree fold_builtin_printf (tree, tree, bool, enum built_in_function); -static tree fold_builtin_fprintf (tree, tree, bool, enum built_in_function); -static bool init_target_chars (void); - -static unsigned HOST_WIDE_INT target_newline; -static unsigned HOST_WIDE_INT target_percent; -static unsigned HOST_WIDE_INT target_c; -static unsigned HOST_WIDE_INT target_s; -static char target_percent_c[3]; -static char target_percent_s[3]; -static char target_percent_s_newline[4]; - -/* Return true if NODE should be considered for inline expansion regardless - of the optimization level. This means whenever a function is invoked with - its "internal" name, which normally contains the prefix "__builtin". */ - -static bool called_as_built_in (tree node) -{ - const char *name = IDENTIFIER_POINTER (DECL_NAME (node)); - if (strncmp (name, "__builtin_", 10) == 0) - return true; - if (strncmp (name, "__sync_", 7) == 0) - return true; - return false; -} /* Return the alignment in bits of EXP, a pointer valued expression. But don't return more than MAX_ALIGN no matter what. @@ -232,11 +179,7 @@ get_pointer_alignment (tree exp, unsigned int max_align) { unsigned int align, inner; - /* We rely on TER to compute accurate alignment information. */ - if (!(optimize && flag_tree_ter)) - return 0; - - if (!POINTER_TYPE_P (TREE_TYPE (exp))) + if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE) return 0; align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))); @@ -250,7 +193,7 @@ get_pointer_alignment (tree exp, unsigned int max_align) case CONVERT_EXPR: case NON_LVALUE_EXPR: exp = TREE_OPERAND (exp, 0); - if (! POINTER_TYPE_P (TREE_TYPE (exp))) + if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE) return align; inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))); @@ -275,59 +218,14 @@ get_pointer_alignment (tree exp, unsigned int max_align) case ADDR_EXPR: /* See what we are pointing at and look at its alignment. */ exp = TREE_OPERAND (exp, 0); - inner = max_align; - if (handled_component_p (exp)) - { - HOST_WIDE_INT bitsize, bitpos; - tree offset; - enum machine_mode mode; - int unsignedp, volatilep; - - exp = get_inner_reference (exp, &bitsize, &bitpos, &offset, - &mode, &unsignedp, &volatilep, true); - if (bitpos) - inner = MIN (inner, (unsigned) (bitpos & -bitpos)); - if (offset && TREE_CODE (offset) == PLUS_EXPR - && host_integerp (TREE_OPERAND (offset, 1), 1)) - { - /* Any overflow in calculating offset_bits won't change - the alignment. */ - unsigned offset_bits - = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1) - * BITS_PER_UNIT); - - if (offset_bits) - inner = MIN (inner, (offset_bits & -offset_bits)); - offset = TREE_OPERAND (offset, 0); - } - if (offset && TREE_CODE (offset) == MULT_EXPR - && host_integerp (TREE_OPERAND (offset, 1), 1)) - { - /* Any overflow in calculating offset_factor won't change - the alignment. */ - unsigned offset_factor - = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1) - * BITS_PER_UNIT); - - if (offset_factor) - inner = MIN (inner, (offset_factor & -offset_factor)); - } - else if (offset) - inner = MIN (inner, BITS_PER_UNIT); - } if (TREE_CODE (exp) == FUNCTION_DECL) align = FUNCTION_BOUNDARY; else if (DECL_P (exp)) - align = MIN (inner, DECL_ALIGN (exp)); + align = DECL_ALIGN (exp); #ifdef CONSTANT_ALIGNMENT - else if (CONSTANT_CLASS_P (exp)) - align = MIN (inner, (unsigned)CONSTANT_ALIGNMENT (exp, align)); + else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c') + align = CONSTANT_ALIGNMENT (exp, align); #endif - else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR - || TREE_CODE (exp) == INDIRECT_REF) - align = MIN (TYPE_ALIGN (TREE_TYPE (exp)), inner); - else - align = MIN (align, inner); return MIN (align, max_align); default: @@ -352,7 +250,7 @@ get_pointer_alignment (tree exp, unsigned int max_align) Unfortunately, string_constant can't access the values of const char arrays with initializers, so neither can we do so here. */ -tree +static tree c_strlen (tree src, int only_value) { tree offset_node; @@ -368,7 +266,7 @@ c_strlen (tree src, int only_value) len1 = c_strlen (TREE_OPERAND (src, 1), only_value); len2 = c_strlen (TREE_OPERAND (src, 2), only_value); - if (tree_int_cst_equal (len1, len2)) + if (tree_int_cst_equal (len1, len2)) return len1; } @@ -417,7 +315,7 @@ c_strlen (tree src, int only_value) runtime. */ if (offset < 0 || offset > max) { - warning (0, "offset outside bounds of constant string"); + warning ("offset outside bounds of constant string"); return 0; } @@ -461,8 +359,8 @@ c_readstr (const char *str, enum machine_mode mode) HOST_WIDE_INT ch; unsigned int i, j; - gcc_assert (GET_MODE_CLASS (mode) == MODE_INT); - + if (GET_MODE_CLASS (mode) != MODE_INT) + abort (); c[0] = 0; c[1] = 0; ch = 1; @@ -475,8 +373,8 @@ c_readstr (const char *str, enum machine_mode mode) && GET_MODE_SIZE (mode) > UNITS_PER_WORD) j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1; j *= BITS_PER_UNIT; - gcc_assert (j <= 2 * HOST_BITS_PER_WIDE_INT); - + if (j > 2 * HOST_BITS_PER_WIDE_INT) + abort (); if (ch) ch = (unsigned char) str[i]; c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT); @@ -485,7 +383,7 @@ c_readstr (const char *str, enum machine_mode mode) } /* Cast a target constant CST to target CHAR and if that value fits into - host char type, return zero and put that value into variable pointed to by + host char type, return zero and put that value into variable pointed by P. */ static int @@ -512,64 +410,25 @@ target_char_cast (tree cst, char *p) return 0; } -/* Similar to save_expr, but assumes that arbitrary code is not executed - in between the multiple evaluations. In particular, we assume that a - non-addressable local variable will not be modified. */ - -static tree -builtin_save_expr (tree exp) -{ - if (TREE_ADDRESSABLE (exp) == 0 - && (TREE_CODE (exp) == PARM_DECL - || (TREE_CODE (exp) == VAR_DECL && !TREE_STATIC (exp)))) - return exp; - - return save_expr (exp); -} - /* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT times to get the address of either a higher stack frame, or a return address located within it (depending on FNDECL_CODE). */ -static rtx -expand_builtin_return_addr (enum built_in_function fndecl_code, int count) +rtx +expand_builtin_return_addr (enum built_in_function fndecl_code, int count, + rtx tem) { int i; -#ifdef INITIAL_FRAME_ADDRESS_RTX - rtx tem = INITIAL_FRAME_ADDRESS_RTX; -#else - rtx tem; - - /* For a zero count with __builtin_return_address, we don't care what - frame address we return, because target-specific definitions will - override us. Therefore frame pointer elimination is OK, and using - the soft frame pointer is OK. - - For a non-zero count, or a zero count with __builtin_frame_address, - we require a stable offset from the current frame pointer to the - previous one, so we must use the hard frame pointer, and - we must disable frame pointer elimination. */ - if (count == 0 && fndecl_code == BUILT_IN_RETURN_ADDRESS) - tem = frame_pointer_rtx; - else - { - tem = hard_frame_pointer_rtx; - - /* Tell reload not to eliminate the frame pointer. */ - current_function_accesses_prior_frames = 1; - } -#endif - /* Some machines need special handling before we can access - arbitrary frames. For example, on the SPARC, we must first flush + arbitrary frames. For example, on the sparc, we must first flush all register windows to the stack. */ #ifdef SETUP_FRAME_ADDRESSES if (count > 0) SETUP_FRAME_ADDRESSES (); #endif - /* On the SPARC, the return address is not in the frame, it is in a + /* On the sparc, the return address is not in the frame, it is in a register. There is no way to access it off of the current frame pointer, but it can be accessed off the previous frame pointer by reading the value from the register window save area. */ @@ -587,26 +446,24 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count) tem = DYNAMIC_CHAIN_ADDRESS (tem); #endif tem = memory_address (Pmode, tem); - tem = gen_frame_mem (Pmode, tem); + tem = gen_rtx_MEM (Pmode, tem); + set_mem_alias_set (tem, get_frame_alias_set ()); tem = copy_to_reg (tem); } - /* For __builtin_frame_address, return what we've got. But, on - the SPARC for example, we may have to add a bias. */ + /* For __builtin_frame_address, return what we've got. */ if (fndecl_code == BUILT_IN_FRAME_ADDRESS) -#ifdef FRAME_ADDR_RTX - return FRAME_ADDR_RTX (tem); -#else return tem; -#endif - /* For __builtin_return_address, get the return address from that frame. */ + /* For __builtin_return_address, Get the return address from that + frame. */ #ifdef RETURN_ADDR_RTX tem = RETURN_ADDR_RTX (count, tem); #else tem = memory_address (Pmode, plus_constant (tem, GET_MODE_SIZE (Pmode))); - tem = gen_frame_mem (Pmode, tem); + tem = gen_rtx_MEM (Pmode, tem); + set_mem_alias_set (tem, get_frame_alias_set ()); #endif return tem; } @@ -615,8 +472,8 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count) static HOST_WIDE_INT setjmp_alias_set = -1; /* Construct the leading half of a __builtin_setjmp call. Control will - return to RECEIVER_LABEL. This is also called directly by the SJLJ - exception handling code. */ + return to RECEIVER_LABEL. This is used directly by sjlj exception + handling code. */ void expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label) @@ -632,13 +489,19 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label) buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX)); + emit_queue (); + /* We store the frame pointer and the address of receiver_label in the buffer and use the rest of it for the stack save area, which is machine-dependent. */ +#ifndef BUILTIN_SETJMP_FRAME_VALUE +#define BUILTIN_SETJMP_FRAME_VALUE virtual_stack_vars_rtx +#endif + mem = gen_rtx_MEM (Pmode, buf_addr); set_mem_alias_set (mem, setjmp_alias_set); - emit_move_insn (mem, targetm.builtin_setjmp_frame_value ()); + emit_move_insn (mem, BUILTIN_SETJMP_FRAME_VALUE); mem = gen_rtx_MEM (Pmode, plus_constant (buf_addr, GET_MODE_SIZE (Pmode))), set_mem_alias_set (mem, setjmp_alias_set); @@ -667,8 +530,8 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label) current_function_has_nonlocal_label = 1; } -/* Construct the trailing part of a __builtin_setjmp call. This is - also called directly by the SJLJ exception handling code. */ +/* Construct the trailing part of a __builtin_setjmp call. + This is used directly by sjlj exception handling code. */ void expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED) @@ -682,16 +545,12 @@ expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED) emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx)); /* Now put in the code to restore the frame pointer, and argument - pointer, if needed. */ + pointer, if needed. The code below is from expand_end_bindings + in stmt.c; see detailed documentation there. */ #ifdef HAVE_nonlocal_goto if (! HAVE_nonlocal_goto) #endif - { - emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx); - /* This might change the hard frame pointer in ways that aren't - apparent to early optimization passes, so force a clobber. */ - emit_insn (gen_rtx_CLOBBER (VOIDmode, hard_frame_pointer_rtx)); - } + emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx); #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM if (fixed_regs[ARG_POINTER_REGNUM]) @@ -736,12 +595,69 @@ expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED) emit_insn (gen_rtx_ASM_INPUT (VOIDmode, "")); } +/* __builtin_setjmp is passed a pointer to an array of five words (not + all will be used on all machines). It operates similarly to the C + library function of the same name, but is more efficient. Much of + the code below (and for longjmp) is copied from the handling of + non-local gotos. + + NOTE: This is intended for use by GNAT and the exception handling + scheme in the compiler and will only work in the method used by + them. */ + +static rtx +expand_builtin_setjmp (tree arglist, rtx target) +{ + rtx buf_addr, next_lab, cont_lab; + + if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) + return NULL_RTX; + + if (target == 0 || GET_CODE (target) != REG + || REGNO (target) < FIRST_PSEUDO_REGISTER) + target = gen_reg_rtx (TYPE_MODE (integer_type_node)); + + buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0); + + next_lab = gen_label_rtx (); + cont_lab = gen_label_rtx (); + + expand_builtin_setjmp_setup (buf_addr, next_lab); + + /* Set TARGET to zero and branch to the continue label. Use emit_jump to + ensure that pending stack adjustments are flushed. */ + emit_move_insn (target, const0_rtx); + emit_jump (cont_lab); + + emit_label (next_lab); + + expand_builtin_setjmp_receiver (next_lab); + + /* Set TARGET to one. */ + emit_move_insn (target, const1_rtx); + emit_label (cont_lab); + + /* Tell flow about the strange goings on. Putting `next_lab' on + `nonlocal_goto_handler_labels' to indicates that function + calls may traverse the arc back to this label. */ + + current_function_has_nonlocal_label = 1; + nonlocal_goto_handler_labels + = gen_rtx_EXPR_LIST (VOIDmode, next_lab, nonlocal_goto_handler_labels); + + return target; +} + /* __builtin_longjmp is passed a pointer to an array of five words (not all will be used on all machines). It operates similarly to the C library function of the same name, but is more efficient. Much of - the code below is copied from the handling of non-local gotos. */ + the code below is copied from the handling of non-local gotos. -static void + NOTE: This is intended for use by GNAT and the exception handling + scheme in the compiler and will only work in the method used by + them. */ + +void expand_builtin_longjmp (rtx buf_addr, rtx value) { rtx fp, lab, stack, insn, last; @@ -759,7 +675,10 @@ expand_builtin_longjmp (rtx buf_addr, rtx value) a second argument of 1, because that is what builtin_setjmp will return. This also makes EH slightly more efficient, since we are no longer copying around a value that we don't care about. */ - gcc_assert (value == const1_rtx); + if (value != const1_rtx) + abort (); + + current_function_calls_longjmp = 1; last = get_last_insn (); #ifdef HAVE_builtin_longjmp @@ -780,7 +699,7 @@ expand_builtin_longjmp (rtx buf_addr, rtx value) /* Pick up FP, label, and SP from the block and jump. This code is from expand_goto in stmt.c; see there for detailed comments. */ -#ifdef HAVE_nonlocal_goto +#if HAVE_nonlocal_goto if (HAVE_nonlocal_goto) /* We have to pass a value to the nonlocal_goto pattern that will get copied into the static_chain pointer, but it does not matter @@ -814,128 +733,19 @@ expand_builtin_longjmp (rtx buf_addr, rtx value) internal exception handling use only. */ for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) { - gcc_assert (insn != last); - - if (JUMP_P (insn)) + if (insn == last) + abort (); + if (GET_CODE (insn) == JUMP_INSN) { REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx, REG_NOTES (insn)); break; } - else if (CALL_P (insn)) + else if (GET_CODE (insn) == CALL_INSN) break; } } -/* Expand a call to __builtin_nonlocal_goto. We're passed the target label - and the address of the save area. */ - -static rtx -expand_builtin_nonlocal_goto (tree arglist) -{ - tree t_label, t_save_area; - rtx r_label, r_save_area, r_fp, r_sp, insn; - - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return NULL_RTX; - - t_label = TREE_VALUE (arglist); - arglist = TREE_CHAIN (arglist); - t_save_area = TREE_VALUE (arglist); - - r_label = expand_normal (t_label); - r_label = convert_memory_address (Pmode, r_label); - r_save_area = expand_normal (t_save_area); - r_save_area = convert_memory_address (Pmode, r_save_area); - r_fp = gen_rtx_MEM (Pmode, r_save_area); - r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL), - plus_constant (r_save_area, GET_MODE_SIZE (Pmode))); - - current_function_has_nonlocal_goto = 1; - -#ifdef HAVE_nonlocal_goto - /* ??? We no longer need to pass the static chain value, afaik. */ - if (HAVE_nonlocal_goto) - emit_insn (gen_nonlocal_goto (const0_rtx, r_label, r_sp, r_fp)); - else -#endif - { - r_label = copy_to_reg (r_label); - - emit_insn (gen_rtx_CLOBBER (VOIDmode, - gen_rtx_MEM (BLKmode, - gen_rtx_SCRATCH (VOIDmode)))); - - emit_insn (gen_rtx_CLOBBER (VOIDmode, - gen_rtx_MEM (BLKmode, - hard_frame_pointer_rtx))); - - /* Restore frame pointer for containing function. - This sets the actual hard register used for the frame pointer - to the location of the function's incoming static chain info. - The non-local goto handler will then adjust it to contain the - proper value and reload the argument pointer, if needed. */ - emit_move_insn (hard_frame_pointer_rtx, r_fp); - emit_stack_restore (SAVE_NONLOCAL, r_sp, NULL_RTX); - - /* USE of hard_frame_pointer_rtx added for consistency; - not clear if really needed. */ - emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); - emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); - emit_indirect_jump (r_label); - } - - /* Search backwards to the jump insn and mark it as a - non-local goto. */ - for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) - { - if (JUMP_P (insn)) - { - REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, - const0_rtx, REG_NOTES (insn)); - break; - } - else if (CALL_P (insn)) - break; - } - - return const0_rtx; -} - -/* __builtin_update_setjmp_buf is passed a pointer to an array of five words - (not all will be used on all machines) that was passed to __builtin_setjmp. - It updates the stack pointer in that block to correspond to the current - stack pointer. */ - -static void -expand_builtin_update_setjmp_buf (rtx buf_addr) -{ - enum machine_mode sa_mode = Pmode; - rtx stack_save; - - -#ifdef HAVE_save_stack_nonlocal - if (HAVE_save_stack_nonlocal) - sa_mode = insn_data[(int) CODE_FOR_save_stack_nonlocal].operand[0].mode; -#endif -#ifdef STACK_SAVEAREA_MODE - sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL); -#endif - - stack_save - = gen_rtx_MEM (sa_mode, - memory_address - (sa_mode, - plus_constant (buf_addr, 2 * GET_MODE_SIZE (Pmode)))); - -#ifdef HAVE_setjmp - if (HAVE_setjmp) - emit_insn (gen_setjmp ()); -#endif - - emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX); -} - /* Expand a call to __builtin_prefetch. For a target that does not support data prefetch, evaluate the memory address argument in case it has side effects. */ @@ -959,12 +769,12 @@ expand_builtin_prefetch (tree arglist) if (TREE_CHAIN (TREE_CHAIN (arglist))) arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); else - arg2 = build_int_cst (NULL_TREE, 3); + arg2 = build_int_2 (3, 0); } else { arg1 = integer_zero_node; - arg2 = build_int_cst (NULL_TREE, 3); + arg2 = build_int_2 (3, 0); } /* Argument 0 is an address. */ @@ -973,29 +783,28 @@ expand_builtin_prefetch (tree arglist) /* Argument 1 (read/write flag) must be a compile-time constant int. */ if (TREE_CODE (arg1) != INTEGER_CST) { - error ("second argument to %<__builtin_prefetch%> must be a constant"); + error ("second arg to `__builtin_prefetch' must be a constant"); arg1 = integer_zero_node; } - op1 = expand_normal (arg1); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); /* Argument 1 must be either zero or one. */ if (INTVAL (op1) != 0 && INTVAL (op1) != 1) { - warning (0, "invalid second argument to %<__builtin_prefetch%>;" - " using zero"); + warning ("invalid second arg to __builtin_prefetch; using zero"); op1 = const0_rtx; } /* Argument 2 (locality) must be a compile-time constant int. */ if (TREE_CODE (arg2) != INTEGER_CST) { - error ("third argument to %<__builtin_prefetch%> must be a constant"); + error ("third arg to `__builtin_prefetch' must be a constant"); arg2 = integer_zero_node; } - op2 = expand_normal (arg2); + op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); /* Argument 2 must be 0, 1, 2, or 3. */ if (INTVAL (op2) < 0 || INTVAL (op2) > 3) { - warning (0, "invalid third argument to %<__builtin_prefetch%>; using zero"); + warning ("invalid third arg to __builtin_prefetch; using zero"); op2 = const0_rtx; } @@ -1012,24 +821,27 @@ expand_builtin_prefetch (tree arglist) } emit_insn (gen_prefetch (op0, op1, op2)); } + else #endif - + op0 = protect_from_queue (op0, 0); /* Don't do anything with direct references to volatile memory, but generate code to handle other side effects. */ - if (!MEM_P (op0) && side_effects_p (op0)) + if (GET_CODE (op0) != MEM && side_effects_p (op0)) emit_insn (op0); } /* Get a MEM rtx for expression EXP which is the address of an operand - to be used in a string instruction (cmpstrsi, movmemsi, ..). LEN is - the maximum length of the block of memory that might be accessed or - NULL if unknown. */ + to be used to be used in a string instruction (cmpstrsi, movstrsi, ..). */ static rtx -get_memory_rtx (tree exp, tree len) +get_memory_rtx (tree exp) { - rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_NORMAL); - rtx mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr)); + rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_SUM); + rtx mem; + + addr = convert_memory_address (Pmode, addr); + + mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr)); /* Get an expression we can use to find the attributes to assign to MEM. If it is an ADDR_EXPR, use the operand. Otherwise, dereference it if @@ -1040,94 +852,15 @@ get_memory_rtx (tree exp, tree len) exp = TREE_OPERAND (exp, 0); if (TREE_CODE (exp) == ADDR_EXPR) - exp = TREE_OPERAND (exp, 0); - else if (POINTER_TYPE_P (TREE_TYPE (exp))) - exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp); - else - exp = NULL; - - /* Honor attributes derived from exp, except for the alias set - (as builtin stringops may alias with anything) and the size - (as stringops may access multiple array elements). */ - if (exp) { + exp = TREE_OPERAND (exp, 0); set_mem_attributes (mem, exp, 0); - - /* Allow the string and memory builtins to overflow from one - field into another, see http://gcc.gnu.org/PR23561. - Thus avoid COMPONENT_REFs in MEM_EXPR unless we know the whole - memory accessed by the string or memory builtin will fit - within the field. */ - if (MEM_EXPR (mem) && TREE_CODE (MEM_EXPR (mem)) == COMPONENT_REF) - { - tree mem_expr = MEM_EXPR (mem); - HOST_WIDE_INT offset = -1, length = -1; - tree inner = exp; - - while (TREE_CODE (inner) == ARRAY_REF - || TREE_CODE (inner) == NOP_EXPR - || TREE_CODE (inner) == CONVERT_EXPR - || TREE_CODE (inner) == NON_LVALUE_EXPR - || TREE_CODE (inner) == VIEW_CONVERT_EXPR - || TREE_CODE (inner) == SAVE_EXPR) - inner = TREE_OPERAND (inner, 0); - - gcc_assert (TREE_CODE (inner) == COMPONENT_REF); - - if (MEM_OFFSET (mem) - && GET_CODE (MEM_OFFSET (mem)) == CONST_INT) - offset = INTVAL (MEM_OFFSET (mem)); - - if (offset >= 0 && len && host_integerp (len, 0)) - length = tree_low_cst (len, 0); - - while (TREE_CODE (inner) == COMPONENT_REF) - { - tree field = TREE_OPERAND (inner, 1); - gcc_assert (! DECL_BIT_FIELD (field)); - gcc_assert (TREE_CODE (mem_expr) == COMPONENT_REF); - gcc_assert (field == TREE_OPERAND (mem_expr, 1)); - - if (length >= 0 - && TYPE_SIZE_UNIT (TREE_TYPE (inner)) - && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0)) - { - HOST_WIDE_INT size - = tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0); - /* If we can prove the memory starting at XEXP (mem, 0) - and ending at XEXP (mem, 0) + LENGTH will fit into - this field, we can keep that COMPONENT_REF in MEM_EXPR. */ - if (offset <= size - && length <= size - && offset + length <= size) - break; - } - - if (offset >= 0 - && host_integerp (DECL_FIELD_OFFSET (field), 0)) - offset += tree_low_cst (DECL_FIELD_OFFSET (field), 0) - + tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1) - / BITS_PER_UNIT; - else - { - offset = -1; - length = -1; - } - - mem_expr = TREE_OPERAND (mem_expr, 0); - inner = TREE_OPERAND (inner, 0); - } - - if (mem_expr == NULL) - offset = -1; - if (mem_expr != MEM_EXPR (mem)) - { - set_mem_expr (mem, mem_expr); - set_mem_offset (mem, offset >= 0 ? GEN_INT (offset) : NULL_RTX); - } - } + } + else if (POINTER_TYPE_P (TREE_TYPE (exp))) + { + exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp); + /* memcpy, memset and other builtin stringops can alias with anything. */ set_mem_alias_set (mem, 0); - set_mem_size (mem, NULL_RTX); } return mem; @@ -1155,6 +888,23 @@ static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER]; used for calling a function. */ static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER]; +/* Return the offset of register REGNO into the block returned by + __builtin_apply_args. This is not declared static, since it is + needed in objc-act.c. */ + +int +apply_args_register_offset (int regno) +{ + apply_args_size (); + + /* Arguments are always put in outgoing registers (in the argument + block) if such make sense. */ +#ifdef OUTGOING_REGNO + regno = OUTGOING_REGNO (regno); +#endif + return apply_args_reg_offset[regno]; +} + /* Return the size required for the block returned by __builtin_apply_args, and initialize apply_args_mode. */ @@ -1180,9 +930,44 @@ apply_args_size (void) for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (FUNCTION_ARG_REGNO_P (regno)) { - mode = reg_raw_mode[regno]; - - gcc_assert (mode != VOIDmode); + /* Search for the proper mode for copying this register's + value. I'm not sure this is right, but it works so far. */ + enum machine_mode best_mode = VOIDmode; + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode) + && HARD_REGNO_NREGS (regno, mode) == 1) + best_mode = mode; + + if (best_mode == VOIDmode) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode) + && have_insn_for (SET, mode)) + best_mode = mode; + + if (best_mode == VOIDmode) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode) + && have_insn_for (SET, mode)) + best_mode = mode; + + if (best_mode == VOIDmode) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode) + && have_insn_for (SET, mode)) + best_mode = mode; + + mode = best_mode; + if (mode == VOIDmode) + abort (); align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; if (size % align != 0) @@ -1218,9 +1003,43 @@ apply_result_size (void) for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (FUNCTION_VALUE_REGNO_P (regno)) { - mode = reg_raw_mode[regno]; - - gcc_assert (mode != VOIDmode); + /* Search for the proper mode for copying this register's + value. I'm not sure this is right, but it works so far. */ + enum machine_mode best_mode = VOIDmode; + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + mode != TImode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode)) + best_mode = mode; + + if (best_mode == VOIDmode) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode) + && have_insn_for (SET, mode)) + best_mode = mode; + + if (best_mode == VOIDmode) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode) + && have_insn_for (SET, mode)) + best_mode = mode; + + if (best_mode == VOIDmode) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode) + && have_insn_for (SET, mode)) + best_mode = mode; + + mode = best_mode; + if (mode == VOIDmode) + abort (); align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; if (size % align != 0) @@ -1316,7 +1135,7 @@ expand_builtin_apply_args_1 (void) NULL_RTX); #endif emit_move_insn (adjust_address (registers, Pmode, 0), tem); - + size = GET_MODE_SIZE (Pmode); /* Save the structure value address unless this is passed as an @@ -1365,7 +1184,7 @@ expand_builtin_apply_args (void) chain current, so the code is placed at the start of the function. */ push_topmost_sequence (); - emit_insn_before (seq, NEXT_INSN (entry_of_function ())); + emit_insn_before (seq, NEXT_INSN (get_insns ())); pop_topmost_sequence (); return temp; } @@ -1397,6 +1216,9 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) incoming_args, 0, OPTAB_LIB_WIDEN); #endif + /* Perform postincrements before actually calling the function. */ + emit_queue (); + /* Push a new argument block and copy the arguments. Do not allow the (potential) memcpy call below to interfere with our stack manipulations. */ @@ -1459,13 +1281,13 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) rtx value = gen_reg_rtx (Pmode); emit_move_insn (value, adjust_address (arguments, Pmode, size)); emit_move_insn (struct_value, value); - if (REG_P (struct_value)) + if (GET_CODE (struct_value) == REG) use_reg (&call_fusage, struct_value); size += GET_MODE_SIZE (Pmode); } /* All arguments and registers used for the call are set up by now! */ - function = prepare_call_address (function, NULL, &call_fusage, 0, 0); + function = prepare_call_address (function, NULL_TREE, &call_fusage, 0, 0); /* Ensure address is valid. SYMBOL_REF is already valid, so no need, and we don't want to load it into a register as an optimization, @@ -1492,8 +1314,8 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if ((mode = apply_result_mode[regno]) != VOIDmode) { - gcc_assert (!valreg); /* HAVE_untyped_call required. */ - + if (valreg) + abort (); /* HAVE_untyped_call required. */ valreg = gen_rtx_REG (mode, regno); } @@ -1505,7 +1327,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) } else #endif - gcc_unreachable (); + abort (); /* Find the CALL insn we just emitted, and attach the register usage information. */ @@ -1586,6 +1408,7 @@ type_to_class (tree type) { case VOID_TYPE: return void_type_class; case INTEGER_TYPE: return integer_type_class; + case CHAR_TYPE: return char_type_class; case ENUMERAL_TYPE: return enumeral_type_class; case BOOLEAN_TYPE: return boolean_type_class; case POINTER_TYPE: return pointer_type_class; @@ -1600,6 +1423,8 @@ type_to_class (tree type) case QUAL_UNION_TYPE: return union_type_class; case ARRAY_TYPE: return (TYPE_STRING_FLAG (type) ? string_type_class : array_type_class); + case SET_TYPE: return set_type_class; + case FILE_TYPE: return file_type_class; case LANG_TYPE: return lang_type_class; default: return no_type_class; } @@ -1616,6 +1441,32 @@ expand_builtin_classify_type (tree arglist) return GEN_INT (no_type_class); } +/* Expand expression EXP, which is a call to __builtin_constant_p. */ + +static rtx +expand_builtin_constant_p (tree arglist, enum machine_mode target_mode) +{ + rtx tmp; + + if (arglist == 0) + return const0_rtx; + arglist = TREE_VALUE (arglist); + + /* We have taken care of the easy cases during constant folding. This + case is not obvious, so emit (constant_p_rtx (ARGLIST)) and let CSE + get a chance to see if it can deduce whether ARGLIST is constant. + If CSE isn't going to run, of course, don't bother waiting. */ + + if (cse_not_expected) + return const0_rtx; + + current_function_calls_constant_p = 1; + + tmp = expand_expr (arglist, NULL_RTX, VOIDmode, 0); + tmp = gen_rtx_CONSTANT_P_RTX (target_mode, tmp); + return tmp; +} + /* This helper macro, meant to be used in mathfn_built_in below, determines which among a set of three builtin math functions is appropriate for a given type mode. The `F' and `L' cases are @@ -1630,6 +1481,7 @@ expand_builtin_classify_type (tree arglist) tree mathfn_built_in (tree type, enum built_in_function fn) { + const enum machine_mode type_mode = TYPE_MODE (type); enum built_in_function fcode, fcodef, fcodel; switch (fn) @@ -1669,12 +1521,8 @@ mathfn_built_in (tree type, enum built_in_function fn) CASE_MATHFN (BUILT_IN_J0) CASE_MATHFN (BUILT_IN_J1) CASE_MATHFN (BUILT_IN_JN) - CASE_MATHFN (BUILT_IN_LCEIL) CASE_MATHFN (BUILT_IN_LDEXP) - CASE_MATHFN (BUILT_IN_LFLOOR) CASE_MATHFN (BUILT_IN_LGAMMA) - CASE_MATHFN (BUILT_IN_LLCEIL) - CASE_MATHFN (BUILT_IN_LLFLOOR) CASE_MATHFN (BUILT_IN_LLRINT) CASE_MATHFN (BUILT_IN_LLROUND) CASE_MATHFN (BUILT_IN_LOG) @@ -1691,7 +1539,6 @@ mathfn_built_in (tree type, enum built_in_function fn) CASE_MATHFN (BUILT_IN_NEXTAFTER) CASE_MATHFN (BUILT_IN_NEXTTOWARD) CASE_MATHFN (BUILT_IN_POW) - CASE_MATHFN (BUILT_IN_POWI) CASE_MATHFN (BUILT_IN_POW10) CASE_MATHFN (BUILT_IN_REMAINDER) CASE_MATHFN (BUILT_IN_REMQUO) @@ -1717,11 +1564,11 @@ mathfn_built_in (tree type, enum built_in_function fn) return 0; } - if (TYPE_MAIN_VARIANT (type) == double_type_node) + if (type_mode == TYPE_MODE (double_type_node)) return implicit_built_in_decls[fcode]; - else if (TYPE_MAIN_VARIANT (type) == float_type_node) + else if (type_mode == TYPE_MODE (float_type_node)) return implicit_built_in_decls[fcodef]; - else if (TYPE_MAIN_VARIANT (type) == long_double_type_node) + else if (type_mode == TYPE_MODE (long_double_type_node)) return implicit_built_in_decls[fcodel]; else return 0; @@ -1766,7 +1613,7 @@ expand_errno_check (tree exp, rtx target) } -/* Expand a call to one of the builtin math functions (sqrt, exp, or log). +/* Expand a call to one of the builtin math functions (sin, cos, or sqrt). Return 0 if a normal call should be emitted rather than expanding the function in-line. EXP is the expression that is a call to the builtin function; if convenient, the result should be placed in TARGET. @@ -1790,56 +1637,58 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) switch (DECL_FUNCTION_CODE (fndecl)) { - CASE_FLT_FN (BUILT_IN_SQRT): + case BUILT_IN_SIN: + case BUILT_IN_SINF: + case BUILT_IN_SINL: + builtin_optab = sin_optab; break; + case BUILT_IN_COS: + case BUILT_IN_COSF: + case BUILT_IN_COSL: + builtin_optab = cos_optab; break; + case BUILT_IN_SQRT: + case BUILT_IN_SQRTF: + case BUILT_IN_SQRTL: errno_set = ! tree_expr_nonnegative_p (arg); builtin_optab = sqrt_optab; break; - CASE_FLT_FN (BUILT_IN_EXP): + case BUILT_IN_EXP: + case BUILT_IN_EXPF: + case BUILT_IN_EXPL: errno_set = true; builtin_optab = exp_optab; break; - CASE_FLT_FN (BUILT_IN_EXP10): - CASE_FLT_FN (BUILT_IN_POW10): - errno_set = true; builtin_optab = exp10_optab; break; - CASE_FLT_FN (BUILT_IN_EXP2): - errno_set = true; builtin_optab = exp2_optab; break; - CASE_FLT_FN (BUILT_IN_EXPM1): - errno_set = true; builtin_optab = expm1_optab; break; - CASE_FLT_FN (BUILT_IN_LOGB): - errno_set = true; builtin_optab = logb_optab; break; - CASE_FLT_FN (BUILT_IN_ILOGB): - errno_set = true; builtin_optab = ilogb_optab; break; - CASE_FLT_FN (BUILT_IN_LOG): + case BUILT_IN_LOG: + case BUILT_IN_LOGF: + case BUILT_IN_LOGL: errno_set = true; builtin_optab = log_optab; break; - CASE_FLT_FN (BUILT_IN_LOG10): - errno_set = true; builtin_optab = log10_optab; break; - CASE_FLT_FN (BUILT_IN_LOG2): - errno_set = true; builtin_optab = log2_optab; break; - CASE_FLT_FN (BUILT_IN_LOG1P): - errno_set = true; builtin_optab = log1p_optab; break; - CASE_FLT_FN (BUILT_IN_ASIN): - builtin_optab = asin_optab; break; - CASE_FLT_FN (BUILT_IN_ACOS): - builtin_optab = acos_optab; break; - CASE_FLT_FN (BUILT_IN_TAN): + case BUILT_IN_TAN: + case BUILT_IN_TANF: + case BUILT_IN_TANL: builtin_optab = tan_optab; break; - CASE_FLT_FN (BUILT_IN_ATAN): + case BUILT_IN_ATAN: + case BUILT_IN_ATANF: + case BUILT_IN_ATANL: builtin_optab = atan_optab; break; - CASE_FLT_FN (BUILT_IN_FLOOR): + case BUILT_IN_FLOOR: + case BUILT_IN_FLOORF: + case BUILT_IN_FLOORL: builtin_optab = floor_optab; break; - CASE_FLT_FN (BUILT_IN_CEIL): + case BUILT_IN_CEIL: + case BUILT_IN_CEILF: + case BUILT_IN_CEILL: builtin_optab = ceil_optab; break; - CASE_FLT_FN (BUILT_IN_TRUNC): + case BUILT_IN_TRUNC: + case BUILT_IN_TRUNCF: + case BUILT_IN_TRUNCL: builtin_optab = btrunc_optab; break; - CASE_FLT_FN (BUILT_IN_ROUND): + case BUILT_IN_ROUND: + case BUILT_IN_ROUNDF: + case BUILT_IN_ROUNDL: builtin_optab = round_optab; break; - CASE_FLT_FN (BUILT_IN_NEARBYINT): + case BUILT_IN_NEARBYINT: + case BUILT_IN_NEARBYINTF: + case BUILT_IN_NEARBYINTL: builtin_optab = nearbyint_optab; break; - CASE_FLT_FN (BUILT_IN_RINT): - builtin_optab = rint_optab; break; - CASE_FLT_FN (BUILT_IN_LRINT): - CASE_FLT_FN (BUILT_IN_LLRINT): - builtin_optab = lrint_optab; break; default: - gcc_unreachable (); + abort (); } /* Make a suitable register to place result in. */ @@ -1856,7 +1705,7 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) /* Wrap the computation of the argument in a SAVE_EXPR, as we may need to expand the argument again. This way, we will not perform side-effects more the once. */ - narg = builtin_save_expr (arg); + narg = save_expr (arg); if (narg != arg) { arg = narg; @@ -1866,6 +1715,7 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) op0 = expand_expr (arg, subtarget, VOIDmode, 0); + emit_queue (); start_sequence (); /* Compute into TARGET. @@ -1919,7 +1769,7 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) rtx operand = XEXP (XEXP (XEXP (note, 0), 1), 0); /* Check operand is a register with expected mode. */ if (operand - && REG_P (operand) + && GET_CODE (operand) == REG && GET_MODE (operand) == mode) { /* Replace the REG_EQUAL note with a SQRT rtx. */ @@ -1948,7 +1798,6 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) { optab builtin_optab; rtx op0, op1, insns; - int op1_type = REAL_TYPE; tree fndecl = get_callee_fndecl (exp); tree arglist = TREE_OPERAND (exp, 1); tree arg0, arg1, temp, narg; @@ -1956,12 +1805,7 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) bool errno_set = true; bool stable = true; - if ((DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXP) - || (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXPF) - || (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXPL)) - op1_type = INTEGER_TYPE; - - if (!validate_arglist (arglist, REAL_TYPE, op1_type, VOID_TYPE)) + if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) return 0; arg0 = TREE_VALUE (arglist); @@ -1969,18 +1813,16 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) switch (DECL_FUNCTION_CODE (fndecl)) { - CASE_FLT_FN (BUILT_IN_POW): + case BUILT_IN_POW: + case BUILT_IN_POWF: + case BUILT_IN_POWL: builtin_optab = pow_optab; break; - CASE_FLT_FN (BUILT_IN_ATAN2): + case BUILT_IN_ATAN2: + case BUILT_IN_ATAN2F: + case BUILT_IN_ATAN2L: builtin_optab = atan2_optab; break; - CASE_FLT_FN (BUILT_IN_LDEXP): - builtin_optab = ldexp_optab; break; - CASE_FLT_FN (BUILT_IN_FMOD): - builtin_optab = fmod_optab; break; - CASE_FLT_FN (BUILT_IN_DREM): - builtin_optab = drem_optab; break; default: - gcc_unreachable (); + abort (); } /* Make a suitable register to place result in. */ @@ -1995,8 +1837,8 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) if (! flag_errno_math || ! HONOR_NANS (mode)) errno_set = false; - /* Always stabilize the argument list. */ - narg = builtin_save_expr (arg1); + /* Alway stabilize the argument list. */ + narg = save_expr (arg1); if (narg != arg1) { arg1 = narg; @@ -2006,7 +1848,7 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) else temp = TREE_CHAIN (arglist); - narg = builtin_save_expr (arg0); + narg = save_expr (arg0); if (narg != arg0) { arg0 = narg; @@ -2019,9 +1861,10 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) if (! stable) exp = build_function_call_expr (fndecl, arglist); - op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL); - op1 = expand_normal (arg1); + op0 = expand_expr (arg0, subtarget, VOIDmode, 0); + op1 = expand_expr (arg1, 0, VOIDmode, 0); + emit_queue (); start_sequence (); /* Compute into TARGET. @@ -2049,266 +1892,6 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) return target; } -/* Expand a call to the builtin sin and cos math functions. - Return 0 if a normal call should be emitted rather than expanding the - function in-line. EXP is the expression that is a call to the builtin - function; if convenient, the result should be placed in TARGET. - SUBTARGET may be used as the target for computing one of EXP's - operands. */ - -static rtx -expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget) -{ - optab builtin_optab; - rtx op0, insns; - tree fndecl = get_callee_fndecl (exp); - tree arglist = TREE_OPERAND (exp, 1); - enum machine_mode mode; - tree arg, narg; - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return 0; - - arg = TREE_VALUE (arglist); - - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_SIN): - CASE_FLT_FN (BUILT_IN_COS): - builtin_optab = sincos_optab; break; - default: - gcc_unreachable (); - } - - /* Make a suitable register to place result in. */ - mode = TYPE_MODE (TREE_TYPE (exp)); - - /* Check if sincos insn is available, otherwise fallback - to sin or cos insn. */ - if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) { - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_SIN): - builtin_optab = sin_optab; break; - CASE_FLT_FN (BUILT_IN_COS): - builtin_optab = cos_optab; break; - default: - gcc_unreachable (); - } - } - - /* Before working hard, check whether the instruction is available. */ - if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) - { - target = gen_reg_rtx (mode); - - /* Wrap the computation of the argument in a SAVE_EXPR, as we may - need to expand the argument again. This way, we will not perform - side-effects more the once. */ - narg = save_expr (arg); - if (narg != arg) - { - arg = narg; - arglist = build_tree_list (NULL_TREE, arg); - exp = build_function_call_expr (fndecl, arglist); - } - - op0 = expand_expr (arg, subtarget, VOIDmode, 0); - - start_sequence (); - - /* Compute into TARGET. - Set TARGET to wherever the result comes back. */ - if (builtin_optab == sincos_optab) - { - int result; - - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_SIN): - result = expand_twoval_unop (builtin_optab, op0, 0, target, 0); - break; - CASE_FLT_FN (BUILT_IN_COS): - result = expand_twoval_unop (builtin_optab, op0, target, 0, 0); - break; - default: - gcc_unreachable (); - } - gcc_assert (result); - } - else - { - target = expand_unop (mode, builtin_optab, op0, target, 0); - } - - if (target != 0) - { - /* Output the entire sequence. */ - insns = get_insns (); - end_sequence (); - emit_insn (insns); - return target; - } - - /* If we were unable to expand via the builtin, stop the sequence - (without outputting the insns) and call to the library function - with the stabilized argument list. */ - end_sequence (); - } - - target = expand_call (exp, target, target == const0_rtx); - - return target; -} - -/* Expand a call to the builtin sincos math function. - Return 0 if a normal call should be emitted rather than expanding the - function in-line. EXP is the expression that is a call to the builtin - function. */ - -static rtx -expand_builtin_sincos (tree exp) -{ - rtx op0, op1, op2, target1, target2; - tree arglist = TREE_OPERAND (exp, 1); - enum machine_mode mode; - tree arg, sinp, cosp; - int result; - - if (!validate_arglist (arglist, REAL_TYPE, - POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return 0; - - arg = TREE_VALUE (arglist); - sinp = TREE_VALUE (TREE_CHAIN (arglist)); - cosp = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - - /* Make a suitable register to place result in. */ - mode = TYPE_MODE (TREE_TYPE (arg)); - - /* Check if sincos insn is available, otherwise emit the call. */ - if (sincos_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) - return NULL_RTX; - - target1 = gen_reg_rtx (mode); - target2 = gen_reg_rtx (mode); - - op0 = expand_normal (arg); - op1 = expand_normal (build_fold_indirect_ref (sinp)); - op2 = expand_normal (build_fold_indirect_ref (cosp)); - - /* Compute into target1 and target2. - Set TARGET to wherever the result comes back. */ - result = expand_twoval_unop (sincos_optab, op0, target2, target1, 0); - gcc_assert (result); - - /* Move target1 and target2 to the memory locations indicated - by op1 and op2. */ - emit_move_insn (op1, target1); - emit_move_insn (op2, target2); - - return const0_rtx; -} - -/* Expand a call to one of the builtin rounding functions (lfloor). - If expanding via optab fails, lower expression to (int)(floor(x)). - EXP is the expression that is a call to the builtin function; - if convenient, the result should be placed in TARGET. SUBTARGET may - be used as the target for computing one of EXP's operands. */ - -static rtx -expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget) -{ - optab builtin_optab; - rtx op0, insns, tmp; - tree fndecl = get_callee_fndecl (exp); - tree arglist = TREE_OPERAND (exp, 1); - enum built_in_function fallback_fn; - tree fallback_fndecl; - enum machine_mode mode; - tree arg, narg; - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - gcc_unreachable (); - - arg = TREE_VALUE (arglist); - - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_LCEIL): - CASE_FLT_FN (BUILT_IN_LLCEIL): - builtin_optab = lceil_optab; - fallback_fn = BUILT_IN_CEIL; - break; - - CASE_FLT_FN (BUILT_IN_LFLOOR): - CASE_FLT_FN (BUILT_IN_LLFLOOR): - builtin_optab = lfloor_optab; - fallback_fn = BUILT_IN_FLOOR; - break; - - default: - gcc_unreachable (); - } - - /* Make a suitable register to place result in. */ - mode = TYPE_MODE (TREE_TYPE (exp)); - - /* Before working hard, check whether the instruction is available. */ - if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) - { - target = gen_reg_rtx (mode); - - /* Wrap the computation of the argument in a SAVE_EXPR, as we may - need to expand the argument again. This way, we will not perform - side-effects more the once. */ - narg = builtin_save_expr (arg); - if (narg != arg) - { - arg = narg; - arglist = build_tree_list (NULL_TREE, arg); - exp = build_function_call_expr (fndecl, arglist); - } - - op0 = expand_expr (arg, subtarget, VOIDmode, 0); - - start_sequence (); - - /* Compute into TARGET. - Set TARGET to wherever the result comes back. */ - target = expand_unop (mode, builtin_optab, op0, target, 0); - - if (target != 0) - { - /* Output the entire sequence. */ - insns = get_insns (); - end_sequence (); - emit_insn (insns); - return target; - } - - /* If we were unable to expand via the builtin, stop the sequence - (without outputting the insns). */ - end_sequence (); - } - - /* Fall back to floating point rounding optab. */ - fallback_fndecl = mathfn_built_in (TREE_TYPE (arg), fallback_fn); - /* We shouldn't get here on targets without TARGET_C99_FUNCTIONS. - ??? Perhaps convert (int)floorf(x) into (int)floor((double)x). */ - gcc_assert (fallback_fndecl != NULL_TREE); - exp = build_function_call_expr (fallback_fndecl, arglist); - - tmp = expand_normal (exp); - - /* Truncate the result of floating point optab to integer - via expand_fix (). */ - target = gen_reg_rtx (mode); - expand_fix (target, tmp, 0); - - return target; -} - /* To evaluate powi(x,n), the floating point value x raised to the constant integer exponent n, we use a hybrid algorithm that combines the "window method" with look-up tables. For an @@ -2322,7 +1905,7 @@ expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget) multiplications to inline before calling the system library's pow function. powi(x,n) requires at worst 2*bits(n)-2 multiplications, so this default never requires calling pow, powf or powl. */ - + #ifndef POWI_MAX_MULTS #define POWI_MAX_MULTS (2*HOST_BITS_PER_WIDE_INT-2) #endif @@ -2439,7 +2022,7 @@ powi_cost (HOST_WIDE_INT n) result++; } } - + return result + powi_lookup_cost (val, cache); } @@ -2457,7 +2040,7 @@ expand_powi_1 (enum machine_mode mode, unsigned HOST_WIDE_INT n, rtx *cache) if (n < POWI_TABLE_SIZE) { if (cache[n]) - return cache[n]; + return cache[n]; target = gen_reg_rtx (mode); cache[n] = target; @@ -2488,7 +2071,7 @@ expand_powi_1 (enum machine_mode mode, unsigned HOST_WIDE_INT n, rtx *cache) /* Expand the RTL to evaluate powi(x,n) in mode MODE. X is the floating point operand in mode MODE, and N is the exponent. This function needs to be kept in sync with powi_cost above. */ - + static rtx expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n) { @@ -2558,74 +2141,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget) } } } - - if (! flag_unsafe_math_optimizations) - return NULL_RTX; - return expand_builtin_mathfn_2 (exp, target, subtarget); -} - -/* Expand a call to the powi built-in mathematical function. Return 0 if - a normal call should be emitted rather than expanding the function - in-line. EXP is the expression that is a call to the builtin - function; if convenient, the result should be placed in TARGET. */ - -static rtx -expand_builtin_powi (tree exp, rtx target, rtx subtarget) -{ - tree arglist = TREE_OPERAND (exp, 1); - tree arg0, arg1; - rtx op0, op1; - enum machine_mode mode; - enum machine_mode mode2; - - if (! validate_arglist (arglist, REAL_TYPE, INTEGER_TYPE, VOID_TYPE)) - return 0; - - arg0 = TREE_VALUE (arglist); - arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - mode = TYPE_MODE (TREE_TYPE (exp)); - - /* Handle constant power. */ - - if (TREE_CODE (arg1) == INTEGER_CST - && ! TREE_CONSTANT_OVERFLOW (arg1)) - { - HOST_WIDE_INT n = TREE_INT_CST_LOW (arg1); - - /* If the exponent is -1, 0, 1 or 2, then expand_powi is exact. - Otherwise, check the number of multiplications required. */ - if ((TREE_INT_CST_HIGH (arg1) == 0 - || TREE_INT_CST_HIGH (arg1) == -1) - && ((n >= -1 && n <= 2) - || (! optimize_size - && powi_cost (n) <= POWI_MAX_MULTS))) - { - op0 = expand_expr (arg0, subtarget, VOIDmode, 0); - op0 = force_reg (mode, op0); - return expand_powi (op0, mode, n); - } - } - - /* Emit a libcall to libgcc. */ - - /* Mode of the 2nd argument must match that of an int. */ - mode2 = mode_for_size (INT_TYPE_SIZE, MODE_INT, 0); - - if (target == NULL_RTX) - target = gen_reg_rtx (mode); - - op0 = expand_expr (arg0, subtarget, mode, 0); - if (GET_MODE (op0) != mode) - op0 = convert_to_mode (mode, op0, 0); - op1 = expand_expr (arg1, 0, mode2, 0); - if (GET_MODE (op1) != mode2) - op1 = convert_to_mode (mode2, op1, 0); - - target = emit_library_call_value (powi_optab->handlers[(int) mode].libfunc, - target, LCT_CONST_MAKE_BLOCK, mode, 2, - op0, mode, op1, mode2); - - return target; + return expand_builtin_mathfn_2 (exp, target, NULL_RTX); } /* Expand expression EXP which is a call to the strlen builtin. Return 0 @@ -2685,7 +2201,7 @@ expand_builtin_strlen (tree arglist, rtx target, /* Make a place to write the result of the instruction. */ result = target; if (! (result != 0 - && REG_P (result) + && GET_CODE (result) == REG && GET_MODE (result) == insn_mode && REGNO (result) >= FIRST_PSEUDO_REGISTER)) result = gen_reg_rtx (insn_mode); @@ -2713,7 +2229,8 @@ expand_builtin_strlen (tree arglist, rtx target, /* Now that we are assured of success, expand the source. */ start_sequence (); - pat = expand_expr (src, src_reg, ptr_mode, EXPAND_NORMAL); + pat = memory_address (BLKmode, + expand_expr (src, src_reg, ptr_mode, EXPAND_SUM)); if (pat != src_reg) emit_move_insn (src_reg, pat); pat = get_insns (); @@ -2741,15 +2258,53 @@ expand_builtin_strlen (tree arglist, rtx target, in TARGET, if convenient (and in mode MODE if that's convenient). */ static rtx -expand_builtin_strstr (tree arglist, tree type, rtx target, enum machine_mode mode) +expand_builtin_strstr (tree arglist, rtx target, enum machine_mode mode) { - if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + else { - tree result = fold_builtin_strstr (arglist, type); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + tree fn; + const char *p1, *p2; + + p2 = c_getstr (s2); + if (p2 == NULL) + return 0; + + p1 = c_getstr (s1); + if (p1 != NULL) + { + const char *r = strstr (p1, p2); + + if (r == NULL) + return const0_rtx; + + /* Return an offset into the constant string argument. */ + return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1), + s1, convert (TREE_TYPE (s1), + ssize_int (r - p1)))), + target, mode, EXPAND_NORMAL); + } + + if (p2[0] == '\0') + return expand_expr (s1, target, mode, EXPAND_NORMAL); + + if (p2[1] != '\0') + return 0; + + fn = implicit_built_in_decls[BUILT_IN_STRCHR]; + if (!fn) + return 0; + + /* New argument list transforming strstr(s1, s2) to + strchr(s1, s2[0]). */ + arglist = + build_tree_list (NULL_TREE, build_int_2 (p2[0], 0)); + arglist = tree_cons (NULL_TREE, s1, arglist); + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } - return 0; } /* Expand a call to the strchr builtin. Return 0 if we failed the @@ -2757,17 +2312,43 @@ expand_builtin_strstr (tree arglist, tree type, rtx target, enum machine_mode mo in TARGET, if convenient (and in mode MODE if that's convenient). */ static rtx -expand_builtin_strchr (tree arglist, tree type, rtx target, enum machine_mode mode) +expand_builtin_strchr (tree arglist, rtx target, enum machine_mode mode) { - if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return 0; + else { - tree result = fold_builtin_strchr (arglist, type); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + const char *p1; + + if (TREE_CODE (s2) != INTEGER_CST) + return 0; + + p1 = c_getstr (s1); + if (p1 != NULL) + { + char c; + const char *r; + + if (target_char_cast (s2, &c)) + return 0; + + r = strchr (p1, c); + + if (r == NULL) + return const0_rtx; + + /* Return an offset into the constant string argument. */ + return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1), + s1, convert (TREE_TYPE (s1), + ssize_int (r - p1)))), + target, mode, EXPAND_NORMAL); + } - /* FIXME: Should use strchrM optab so that ports can optimize this. */ + /* FIXME: Should use here strchrM optab so that ports can optimize + this. */ + return 0; } - return 0; } /* Expand a call to the strrchr builtin. Return 0 if we failed the @@ -2775,15 +2356,51 @@ expand_builtin_strchr (tree arglist, tree type, rtx target, enum machine_mode mo in TARGET, if convenient (and in mode MODE if that's convenient). */ static rtx -expand_builtin_strrchr (tree arglist, tree type, rtx target, enum machine_mode mode) +expand_builtin_strrchr (tree arglist, rtx target, enum machine_mode mode) { - if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return 0; + else { - tree result = fold_builtin_strrchr (arglist, type); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + tree fn; + const char *p1; + + if (TREE_CODE (s2) != INTEGER_CST) + return 0; + + p1 = c_getstr (s1); + if (p1 != NULL) + { + char c; + const char *r; + + if (target_char_cast (s2, &c)) + return 0; + + r = strrchr (p1, c); + + if (r == NULL) + return const0_rtx; + + /* Return an offset into the constant string argument. */ + return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1), + s1, convert (TREE_TYPE (s1), + ssize_int (r - p1)))), + target, mode, EXPAND_NORMAL); + } + + if (! integer_zerop (s2)) + return 0; + + fn = implicit_built_in_decls[BUILT_IN_STRCHR]; + if (!fn) + return 0; + + /* Transform strrchr(s1, '\0') to strchr(s1, '\0'). */ + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } - return 0; } /* Expand a call to the strpbrk builtin. Return 0 if we failed the @@ -2791,15 +2408,59 @@ expand_builtin_strrchr (tree arglist, tree type, rtx target, enum machine_mode m in TARGET, if convenient (and in mode MODE if that's convenient). */ static rtx -expand_builtin_strpbrk (tree arglist, tree type, rtx target, enum machine_mode mode) +expand_builtin_strpbrk (tree arglist, rtx target, enum machine_mode mode) { - if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + else { - tree result = fold_builtin_strpbrk (arglist, type); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + tree fn; + const char *p1, *p2; + + p2 = c_getstr (s2); + if (p2 == NULL) + return 0; + + p1 = c_getstr (s1); + if (p1 != NULL) + { + const char *r = strpbrk (p1, p2); + + if (r == NULL) + return const0_rtx; + + /* Return an offset into the constant string argument. */ + return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1), + s1, convert (TREE_TYPE (s1), + ssize_int (r - p1)))), + target, mode, EXPAND_NORMAL); + } + + if (p2[0] == '\0') + { + /* strpbrk(x, "") == NULL. + Evaluate and ignore the arguments in case they had + side-effects. */ + expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL); + return const0_rtx; + } + + if (p2[1] != '\0') + return 0; /* Really call strpbrk. */ + + fn = implicit_built_in_decls[BUILT_IN_STRCHR]; + if (!fn) + return 0; + + /* New argument list transforming strpbrk(s1, s2) to + strchr(s1, s2[0]). */ + arglist = + build_tree_list (NULL_TREE, build_int_2 (p2[0], 0)); + arglist = tree_cons (NULL_TREE, s1, arglist); + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } - return 0; } /* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE) @@ -2812,9 +2473,10 @@ builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset, { const char *str = (const char *) data; - gcc_assert (offset >= 0 - && ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode) - <= strlen (str) + 1)); + if (offset < 0 + || ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode) + > strlen (str) + 1)) + abort (); /* Attempt to read past the end of constant string. */ return c_readstr (str + offset, mode); } @@ -2824,10 +2486,8 @@ builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset, otherwise try to get the result in TARGET, if convenient (and in mode MODE if that's convenient). */ static rtx -expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) +expand_builtin_memcpy (tree arglist, rtx target, enum machine_mode mode) { - tree fndecl = get_callee_fndecl (exp); - tree arglist = TREE_OPERAND (exp, 1); if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; @@ -2841,32 +2501,35 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) unsigned int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); rtx dest_mem, src_mem, dest_addr, len_rtx; - tree result = fold_builtin_memory_op (arglist, TREE_TYPE (TREE_TYPE (fndecl)), - false, /*endp=*/0); - - if (result) - { - while (TREE_CODE (result) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); - } - return expand_expr (result, target, mode, EXPAND_NORMAL); - } /* If DEST is not a pointer type, call the normal function. */ if (dest_align == 0) return 0; + /* If the LEN parameter is zero, return DEST. */ + if (integer_zerop (len)) + { + /* Evaluate and ignore SRC in case it has side-effects. */ + expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (dest, target, mode, EXPAND_NORMAL); + } + + /* If SRC and DEST are the same (and not volatile), return DEST. */ + if (operand_equal_p (src, dest, 0)) + { + /* Evaluate and ignore LEN in case it has side-effects. */ + expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (dest, target, mode, EXPAND_NORMAL); + } + /* If either SRC is not a pointer type, don't do this - operation in-line. */ + operation in-line. */ if (src_align == 0) return 0; - dest_mem = get_memory_rtx (dest, len); + dest_mem = get_memory_rtx (dest); set_mem_align (dest_mem, dest_align); - len_rtx = expand_normal (len); + len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); src_str = c_getstr (src); /* If SRC is a string constant and block move would be done @@ -2886,13 +2549,12 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) return dest_mem; } - src_mem = get_memory_rtx (src, len); + src_mem = get_memory_rtx (src); set_mem_align (src_mem, src_align); /* Copy word part most expediently. */ dest_addr = emit_block_move (dest_mem, src_mem, len_rtx, - CALL_EXPR_TAILCALL (exp) - ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL); + BLOCK_OP_NORMAL); if (dest_addr == 0) { @@ -2904,7 +2566,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) } /* Expand a call to the mempcpy builtin, with arguments in ARGLIST. - Return 0 if we failed; the caller should emit a normal call, + Return 0 if we failed the caller should emit a normal call, otherwise try to get the result in TARGET, if convenient (and in mode MODE if that's convenient). If ENDP is 0 return the destination pointer, if ENDP is 1 return the end pointer ala @@ -2912,7 +2574,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) stpcpy. */ static rtx -expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode mode, +expand_builtin_mempcpy (tree arglist, rtx target, enum machine_mode mode, int endp) { if (!validate_arglist (arglist, @@ -2939,29 +2601,49 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m unsigned int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); rtx dest_mem, src_mem, len_rtx; - tree result = fold_builtin_memory_op (arglist, type, false, endp); - if (result) + /* If DEST is not a pointer type, call the normal function. */ + if (dest_align == 0) + return 0; + + /* If SRC and DEST are the same (and not volatile), do nothing. */ + if (operand_equal_p (src, dest, 0)) { - while (TREE_CODE (result) == COMPOUND_EXPR) + tree expr; + + if (endp == 0) { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); + /* Evaluate and ignore LEN in case it has side-effects. */ + expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (dest, target, mode, EXPAND_NORMAL); } - return expand_expr (result, target, mode, EXPAND_NORMAL); - } - /* If either SRC or DEST is not a pointer type, don't do this - operation in-line. */ - if (dest_align == 0 || src_align == 0) - return 0; + if (endp == 2) + len = fold (build (MINUS_EXPR, TREE_TYPE (len), dest, + integer_one_node)); + len = convert (TREE_TYPE (dest), len); + expr = fold (build (PLUS_EXPR, TREE_TYPE (dest), dest, len)); + return expand_expr (expr, target, mode, EXPAND_NORMAL); + } /* If LEN is not constant, call the normal function. */ if (! host_integerp (len, 1)) return 0; + + /* If the LEN parameter is zero, return DEST. */ + if (tree_low_cst (len, 1) == 0) + { + /* Evaluate and ignore SRC in case it has side-effects. */ + expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (dest, target, mode, EXPAND_NORMAL); + } + + /* If either SRC is not a pointer type, don't do this + operation in-line. */ + if (src_align == 0) + return 0; - len_rtx = expand_normal (len); + len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); src_str = c_getstr (src); /* If SRC is a string constant and block move would be done @@ -2973,7 +2655,7 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str, (void *) src_str, dest_align)) { - dest_mem = get_memory_rtx (dest, len); + dest_mem = get_memory_rtx (dest); set_mem_align (dest_mem, dest_align); dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx), builtin_memcpy_read_str, @@ -2987,9 +2669,9 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m && can_move_by_pieces (INTVAL (len_rtx), MIN (dest_align, src_align))) { - dest_mem = get_memory_rtx (dest, len); + dest_mem = get_memory_rtx (dest); set_mem_align (dest_mem, dest_align); - src_mem = get_memory_rtx (src, len); + src_mem = get_memory_rtx (src); set_mem_align (src_mem, src_align); dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx), MIN (dest_align, src_align), endp); @@ -3003,11 +2685,10 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m } /* Expand expression EXP, which is a call to the memmove builtin. Return 0 - if we failed; the caller should emit a normal call. */ + if we failed the caller should emit a normal call. */ static rtx -expand_builtin_memmove (tree arglist, tree type, rtx target, - enum machine_mode mode, tree orig_exp) +expand_builtin_memmove (tree arglist, rtx target, enum machine_mode mode) { if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) @@ -3021,49 +2702,41 @@ expand_builtin_memmove (tree arglist, tree type, rtx target, unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT); unsigned int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); - tree result = fold_builtin_memory_op (arglist, type, false, /*endp=*/3); - - if (result) - { - while (TREE_CODE (result) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); - } - return expand_expr (result, target, mode, EXPAND_NORMAL); - } /* If DEST is not a pointer type, call the normal function. */ if (dest_align == 0) return 0; + /* If the LEN parameter is zero, return DEST. */ + if (integer_zerop (len)) + { + /* Evaluate and ignore SRC in case it has side-effects. */ + expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (dest, target, mode, EXPAND_NORMAL); + } + + /* If SRC and DEST are the same (and not volatile), return DEST. */ + if (operand_equal_p (src, dest, 0)) + { + /* Evaluate and ignore LEN in case it has side-effects. */ + expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (dest, target, mode, EXPAND_NORMAL); + } + /* If either SRC is not a pointer type, don't do this - operation in-line. */ + operation in-line. */ if (src_align == 0) return 0; /* If src is categorized for a readonly section we can use normal memcpy. */ if (readonly_data_expr (src)) - { - tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; + { + tree const fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; if (!fn) return 0; - fn = build_function_call_expr (fn, arglist); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp); - return expand_expr (fn, target, mode, EXPAND_NORMAL); - } - - /* If length is 1 and we can expand memcpy call inline, - it is ok to use memcpy as well. */ - if (integer_onep (len)) - { - rtx ret = expand_builtin_mempcpy (arglist, type, target, mode, - /*endp=*/0); - if (ret) - return ret; + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } /* Otherwise, call the normal function. */ @@ -3075,10 +2748,8 @@ expand_builtin_memmove (tree arglist, tree type, rtx target, if we failed the caller should emit a normal call. */ static rtx -expand_builtin_bcopy (tree exp) +expand_builtin_bcopy (tree arglist) { - tree arglist = TREE_OPERAND (exp, 1); - tree type = TREE_TYPE (exp); tree src, dest, size, newarglist; if (!validate_arglist (arglist, @@ -3094,107 +2765,47 @@ expand_builtin_bcopy (tree exp) so that if it isn't expanded inline, we fallback to calling bcopy instead of memmove. */ - newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size)); + newarglist = build_tree_list (NULL_TREE, convert (sizetype, size)); newarglist = tree_cons (NULL_TREE, src, newarglist); newarglist = tree_cons (NULL_TREE, dest, newarglist); - return expand_builtin_memmove (newarglist, type, const0_rtx, VOIDmode, exp); + return expand_builtin_memmove (newarglist, const0_rtx, VOIDmode); } -#ifndef HAVE_movstr -# define HAVE_movstr 0 -# define CODE_FOR_movstr CODE_FOR_nothing -#endif - -/* Expand into a movstr instruction, if one is available. Return 0 if - we failed, the caller should emit a normal call, otherwise try to - get the result in TARGET, if convenient. If ENDP is 0 return the - destination pointer, if ENDP is 1 return the end pointer ala - mempcpy, and if ENDP is 2 return the end pointer minus one ala - stpcpy. */ +/* Expand expression EXP, which is a call to the strcpy builtin. Return 0 + if we failed the caller should emit a normal call, otherwise try to get + the result in TARGET, if convenient (and in mode MODE if that's + convenient). */ static rtx -expand_movstr (tree dest, tree src, rtx target, int endp) +expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode) { - rtx end; - rtx dest_mem; - rtx src_mem; - rtx insn; - const struct insn_data * data; + tree fn, len, src, dst; - if (!HAVE_movstr) + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; - dest_mem = get_memory_rtx (dest, NULL); - src_mem = get_memory_rtx (src, NULL); - if (!endp) - { - target = force_reg (Pmode, XEXP (dest_mem, 0)); - dest_mem = replace_equiv_address (dest_mem, target); - end = gen_reg_rtx (Pmode); - } - else - { - if (target == 0 || target == const0_rtx) - { - end = gen_reg_rtx (Pmode); - if (target == 0) - target = end; - } - else - end = target; - } - - data = insn_data + CODE_FOR_movstr; - - if (data->operand[0].mode != VOIDmode) - end = gen_lowpart (data->operand[0].mode, end); - - insn = data->genfun (end, dest_mem, src_mem); - - gcc_assert (insn); - - emit_insn (insn); - - /* movstr is supposed to set end to the address of the NUL - terminator. If the caller requested a mempcpy-like return value, - adjust it. */ - if (endp == 1 && target != const0_rtx) - { - rtx tem = plus_constant (gen_lowpart (GET_MODE (target), end), 1); - emit_move_insn (target, force_operand (tem, NULL_RTX)); - } + src = TREE_VALUE (TREE_CHAIN (arglist)); + dst = TREE_VALUE (arglist); - return target; -} + /* If SRC and DST are equal (and not volatile), return DST. */ + if (operand_equal_p (src, dst, 0)) + return expand_expr (dst, target, mode, EXPAND_NORMAL); -/* Expand expression EXP, which is a call to the strcpy builtin. Return 0 - if we failed the caller should emit a normal call, otherwise try to get - the result in TARGET, if convenient (and in mode MODE if that's - convenient). */ + fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; + if (!fn) + return 0; -static rtx -expand_builtin_strcpy (tree fndecl, tree arglist, rtx target, enum machine_mode mode) -{ - if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - { - tree result = fold_builtin_strcpy (fndecl, arglist, 0); - if (result) - { - while (TREE_CODE (result) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); - } - return expand_expr (result, target, mode, EXPAND_NORMAL); - } + len = c_strlen (src, 1); + if (len == 0 || TREE_SIDE_EFFECTS (len)) + return 0; - return expand_movstr (TREE_VALUE (arglist), - TREE_VALUE (TREE_CHAIN (arglist)), - target, /*endp=*/0); - } - return 0; + len = size_binop (PLUS_EXPR, len, ssize_int (1)); + arglist = build_tree_list (NULL_TREE, len); + arglist = tree_cons (NULL_TREE, src, arglist); + arglist = tree_cons (NULL_TREE, dst, arglist); + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } /* Expand a call to the stpcpy builtin, with arguments in ARGLIST. @@ -3203,82 +2814,39 @@ expand_builtin_strcpy (tree fndecl, tree arglist, rtx target, enum machine_mode mode MODE if that's convenient). */ static rtx -expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode) +expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode) { - tree arglist = TREE_OPERAND (exp, 1); - /* If return value is ignored, transform stpcpy into strcpy. */ - if (target == const0_rtx) - { - tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; - if (!fn) - return 0; - - return expand_expr (build_function_call_expr (fn, arglist), - target, mode, EXPAND_NORMAL); - } - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; else { - tree dst, src, len, lenp1; - tree narglist; - rtx ret; + tree dst, src, len; + + /* If return value is ignored, transform stpcpy into strcpy. */ + if (target == const0_rtx) + { + tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; + if (!fn) + return 0; + + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); + } /* Ensure we get an actual string whose length can be evaluated at - compile-time, not an expression containing a string. This is - because the latter will potentially produce pessimized code - when used to produce the return value. */ + compile-time, not an expression containing a string. This is + because the latter will potentially produce pessimized code + when used to produce the return value. */ src = TREE_VALUE (TREE_CHAIN (arglist)); if (! c_getstr (src) || ! (len = c_strlen (src, 0))) - return expand_movstr (TREE_VALUE (arglist), - TREE_VALUE (TREE_CHAIN (arglist)), - target, /*endp=*/2); + return 0; dst = TREE_VALUE (arglist); - lenp1 = size_binop (PLUS_EXPR, len, ssize_int (1)); - narglist = build_tree_list (NULL_TREE, lenp1); - narglist = tree_cons (NULL_TREE, src, narglist); - narglist = tree_cons (NULL_TREE, dst, narglist); - ret = expand_builtin_mempcpy (narglist, TREE_TYPE (exp), - target, mode, /*endp=*/2); - - if (ret) - return ret; - - if (TREE_CODE (len) == INTEGER_CST) - { - rtx len_rtx = expand_normal (len); - - if (GET_CODE (len_rtx) == CONST_INT) - { - ret = expand_builtin_strcpy (get_callee_fndecl (exp), - arglist, target, mode); - - if (ret) - { - if (! target) - { - if (mode != VOIDmode) - target = gen_reg_rtx (mode); - else - target = gen_reg_rtx (GET_MODE (ret)); - } - if (GET_MODE (target) != GET_MODE (ret)) - ret = gen_lowpart (GET_MODE (target), ret); - - ret = plus_constant (ret, INTVAL (len_rtx)); - ret = emit_move_insn (target, force_operand (ret, NULL_RTX)); - gcc_assert (ret); - - return target; - } - } - } - - return expand_movstr (TREE_VALUE (arglist), - TREE_VALUE (TREE_CHAIN (arglist)), - target, /*endp=*/2); + len = fold (size_binop (PLUS_EXPR, len, ssize_int (1))); + arglist = build_tree_list (NULL_TREE, len); + arglist = tree_cons (NULL_TREE, src, arglist); + arglist = tree_cons (NULL_TREE, dst, arglist); + return expand_builtin_mempcpy (arglist, target, mode, /*endp=*/2); } } @@ -3302,36 +2870,41 @@ builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset, if we failed the caller should emit a normal call. */ static rtx -expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode) +expand_builtin_strncpy (tree arglist, rtx target, enum machine_mode mode) { - tree fndecl = get_callee_fndecl (exp); - tree arglist = TREE_OPERAND (exp, 1); - if (validate_arglist (arglist, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, + POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return 0; + else { tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 1); tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - tree result = fold_builtin_strncpy (fndecl, arglist, slen); + tree fn; - if (result) + /* We must be passed a constant len parameter. */ + if (TREE_CODE (len) != INTEGER_CST) + return 0; + + /* If the len parameter is zero, return the dst parameter. */ + if (integer_zerop (len)) { - while (TREE_CODE (result) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); - } - return expand_expr (result, target, mode, EXPAND_NORMAL); + /* Evaluate and ignore the src argument in case it has + side-effects. */ + expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx, + VOIDmode, EXPAND_NORMAL); + /* Return the dst parameter. */ + return expand_expr (TREE_VALUE (arglist), target, mode, + EXPAND_NORMAL); } - /* We must be passed a constant len and src parameter. */ - if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1)) + /* Now, we must be passed a constant src ptr parameter. */ + if (slen == 0 || TREE_CODE (slen) != INTEGER_CST) return 0; slen = size_binop (PLUS_EXPR, slen, ssize_int (1)); /* We're required to pad with trailing zeros if the requested - len is greater than strlen(s2)+1. In that case try to + len is greater than strlen(s2)+1. In that case try to use store_by_pieces, if it fails, punt. */ if (tree_int_cst_lt (slen, len)) { @@ -3347,7 +2920,7 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode) (void *) p, dest_align)) return 0; - dest_mem = get_memory_rtx (dest, len); + dest_mem = get_memory_rtx (dest); store_by_pieces (dest_mem, tree_low_cst (len, 1), builtin_strncpy_read_str, (void *) p, dest_align, 0); @@ -3355,8 +2928,14 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode) dest_mem = convert_memory_address (ptr_mode, dest_mem); return dest_mem; } + + /* OK transform into builtin memcpy. */ + fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; + if (!fn) + return 0; + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } - return 0; } /* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE) @@ -3407,8 +2986,7 @@ builtin_memset_gen_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED, convenient). */ static rtx -expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode, - tree orig_exp) +expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode) { if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)) @@ -3418,13 +2996,11 @@ expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode, tree dest = TREE_VALUE (arglist); tree val = TREE_VALUE (TREE_CHAIN (arglist)); tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - tree fndecl, fn; - enum built_in_function fcode; char c; - unsigned int dest_align; - rtx dest_mem, dest_addr, len_rtx; - dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); + unsigned int dest_align + = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); + rtx dest_mem, dest_addr, len_rtx; /* If DEST is not a pointer type, don't do this operation in-line. */ @@ -3439,69 +3015,64 @@ expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode, return expand_expr (dest, target, mode, EXPAND_NORMAL); } - /* Stabilize the arguments in case we fail. */ - dest = builtin_save_expr (dest); - val = builtin_save_expr (val); - len = builtin_save_expr (len); - - len_rtx = expand_normal (len); - dest_mem = get_memory_rtx (dest, len); - if (TREE_CODE (val) != INTEGER_CST) { rtx val_rtx; - val_rtx = expand_normal (val); - val_rtx = convert_to_mode (TYPE_MODE (unsigned_char_type_node), - val_rtx, 0); + if (!host_integerp (len, 1)) + return 0; + + if (optimize_size && tree_low_cst (len, 1) > 1) + return 0; /* Assume that we can memset by pieces if we can store the * the coefficients by pieces (in the required modes). * We can't pass builtin_memset_gen_str as that emits RTL. */ c = 1; - if (host_integerp (len, 1) - && !(optimize_size && tree_low_cst (len, 1) > 1) - && can_store_by_pieces (tree_low_cst (len, 1), - builtin_memset_read_str, &c, dest_align)) - { - val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node), - val_rtx); - store_by_pieces (dest_mem, tree_low_cst (len, 1), - builtin_memset_gen_str, val_rtx, dest_align, 0); - } - else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx, - dest_align)) - goto do_libcall; + if (!can_store_by_pieces (tree_low_cst (len, 1), + builtin_memset_read_str, + &c, dest_align)) + return 0; + val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val)); + val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0); + val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node), + val_rtx); + dest_mem = get_memory_rtx (dest); + store_by_pieces (dest_mem, tree_low_cst (len, 1), + builtin_memset_gen_str, + val_rtx, dest_align, 0); dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); dest_mem = convert_memory_address (ptr_mode, dest_mem); return dest_mem; } if (target_char_cast (val, &c)) - goto do_libcall; + return 0; if (c) { - if (host_integerp (len, 1) - && !(optimize_size && tree_low_cst (len, 1) > 1) - && can_store_by_pieces (tree_low_cst (len, 1), - builtin_memset_read_str, &c, dest_align)) - store_by_pieces (dest_mem, tree_low_cst (len, 1), - builtin_memset_read_str, &c, dest_align, 0); - else if (!set_storage_via_setmem (dest_mem, len_rtx, GEN_INT (c), - dest_align)) - goto do_libcall; + if (!host_integerp (len, 1)) + return 0; + if (!can_store_by_pieces (tree_low_cst (len, 1), + builtin_memset_read_str, &c, + dest_align)) + return 0; + dest_mem = get_memory_rtx (dest); + store_by_pieces (dest_mem, tree_low_cst (len, 1), + builtin_memset_read_str, + &c, dest_align, 0); dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); dest_mem = convert_memory_address (ptr_mode, dest_mem); return dest_mem; } + len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); + + dest_mem = get_memory_rtx (dest); set_mem_align (dest_mem, dest_align); - dest_addr = clear_storage (dest_mem, len_rtx, - CALL_EXPR_TAILCALL (orig_exp) - ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL); + dest_addr = clear_storage (dest_mem, len_rtx); if (dest_addr == 0) { @@ -3510,19 +3081,6 @@ expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode, } return dest_addr; - - do_libcall: - fndecl = get_callee_fndecl (orig_exp); - fcode = DECL_FUNCTION_CODE (fndecl); - gcc_assert (fcode == BUILT_IN_MEMSET || fcode == BUILT_IN_BZERO); - arglist = build_tree_list (NULL_TREE, len); - if (fcode == BUILT_IN_MEMSET) - arglist = tree_cons (NULL_TREE, val, arglist); - arglist = tree_cons (NULL_TREE, dest, arglist); - fn = build_function_call_expr (fndecl, arglist); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp); - return expand_call (fn, target, target == const0_rtx); } } @@ -3530,9 +3088,8 @@ expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode, if we failed the caller should emit a normal call. */ static rtx -expand_builtin_bzero (tree exp) +expand_builtin_bzero (tree arglist) { - tree arglist = TREE_OPERAND (exp, 1); tree dest, size, newarglist; if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) @@ -3546,11 +3103,11 @@ expand_builtin_bzero (tree exp) so that if it isn't expanded inline, we fallback to calling bzero instead of memset. */ - newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size)); + newarglist = build_tree_list (NULL_TREE, convert (sizetype, size)); newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist); newarglist = tree_cons (NULL_TREE, dest, newarglist); - return expand_builtin_memset (newarglist, const0_rtx, VOIDmode, exp); + return expand_builtin_memset (newarglist, const0_rtx, VOIDmode); } /* Expand expression EXP, which is a call to the memcmp built-in function. @@ -3562,21 +3119,69 @@ static rtx expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, enum machine_mode mode) { + tree arg1, arg2, len; + const char *p1, *p2; + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; - else + + arg1 = TREE_VALUE (arglist); + arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + + /* If the len parameter is zero, return zero. */ + if (integer_zerop (len)) + { + /* Evaluate and ignore arg1 and arg2 in case they have + side-effects. */ + expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL); + expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL); + return const0_rtx; + } + + /* If both arguments are equal (and not volatile), return zero. */ + if (operand_equal_p (arg1, arg2, 0)) { - tree result = fold_builtin_memcmp (arglist); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); + /* Evaluate and ignore len in case it has side-effects. */ + expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL); + return const0_rtx; } -#if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi + p1 = c_getstr (arg1); + p2 = c_getstr (arg2); + + /* If all arguments are constant, and the value of len is not greater + than the lengths of arg1 and arg2, evaluate at compile-time. */ + if (host_integerp (len, 1) && p1 && p2 + && compare_tree_int (len, strlen (p1) + 1) <= 0 + && compare_tree_int (len, strlen (p2) + 1) <= 0) + { + const int r = memcmp (p1, p2, tree_low_cst (len, 1)); + + return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx)); + } + + /* If len parameter is one, return an expression corresponding to + (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */ + if (integer_onep (len)) + { + tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); + tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node); + tree ind1 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg1)))); + tree ind2 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg2)))); + tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2)); + return expand_expr (result, target, mode, EXPAND_NORMAL); + } + +#if defined HAVE_cmpmemsi || defined HAVE_cmpstrsi { - tree arg1 = TREE_VALUE (arglist); - tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); - tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); rtx arg1_rtx, arg2_rtx, arg3_rtx; rtx result; rtx insn; @@ -3592,12 +3197,12 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode; else #endif -#ifdef HAVE_cmpstrnsi - if (HAVE_cmpstrnsi) - insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode; +#ifdef HAVE_cmpstrsi + if (HAVE_cmpstrsi) + insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; else #endif - return 0; + return 0; /* If we don't have POINTER_TYPE, call the function. */ if (arg1_align == 0 || arg2_align == 0) @@ -3606,34 +3211,26 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, /* Make a place to write the result of the instruction. */ result = target; if (! (result != 0 - && REG_P (result) && GET_MODE (result) == insn_mode + && GET_CODE (result) == REG && GET_MODE (result) == insn_mode && REGNO (result) >= FIRST_PSEUDO_REGISTER)) result = gen_reg_rtx (insn_mode); - arg1_rtx = get_memory_rtx (arg1, len); - arg2_rtx = get_memory_rtx (arg2, len); - arg3_rtx = expand_normal (len); - - /* Set MEM_SIZE as appropriate. */ - if (GET_CODE (arg3_rtx) == CONST_INT) - { - set_mem_size (arg1_rtx, arg3_rtx); - set_mem_size (arg2_rtx, arg3_rtx); - } - + arg1_rtx = get_memory_rtx (arg1); + arg2_rtx = get_memory_rtx (arg2); + arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); #ifdef HAVE_cmpmemsi if (HAVE_cmpmemsi) insn = gen_cmpmemsi (result, arg1_rtx, arg2_rtx, arg3_rtx, GEN_INT (MIN (arg1_align, arg2_align))); else #endif -#ifdef HAVE_cmpstrnsi - if (HAVE_cmpstrnsi) - insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx, - GEN_INT (MIN (arg1_align, arg2_align))); +#ifdef HAVE_cmpstrsi + if (HAVE_cmpstrsi) + insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx, + GEN_INT (MIN (arg1_align, arg2_align))); else #endif - gcc_unreachable (); + abort (); if (insn) emit_insn (insn); @@ -3643,7 +3240,7 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, XEXP (arg1_rtx, 0), Pmode, XEXP (arg2_rtx, 0), Pmode, convert_to_mode (TYPE_MODE (sizetype), arg3_rtx, - TYPE_UNSIGNED (sizetype)), + TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype)); /* Return the value in the proper mode for this function. */ @@ -3671,146 +3268,139 @@ static rtx expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) { tree arglist = TREE_OPERAND (exp, 1); + tree arg1, arg2; + const char *p1, *p2; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; - else + + arg1 = TREE_VALUE (arglist); + arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + + /* If both arguments are equal (and not volatile), return zero. */ + if (operand_equal_p (arg1, arg2, 0)) + return const0_rtx; + + p1 = c_getstr (arg1); + p2 = c_getstr (arg2); + + if (p1 && p2) { - tree result = fold_builtin_strcmp (arglist); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); + const int i = strcmp (p1, p2); + return (i < 0 ? constm1_rtx : (i > 0 ? const1_rtx : const0_rtx)); } -#if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi - if (cmpstr_optab[SImode] != CODE_FOR_nothing - || cmpstrn_optab[SImode] != CODE_FOR_nothing) + /* If either arg is "", return an expression corresponding to + (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */ + if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')) { - rtx arg1_rtx, arg2_rtx; - rtx result, insn = NULL_RTX; - tree fndecl, fn; - - tree arg1 = TREE_VALUE (arglist); - tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); - int arg1_align - = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - int arg2_align - = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - - /* If we don't have POINTER_TYPE, call the function. */ - if (arg1_align == 0 || arg2_align == 0) - return 0; + tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); + tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node); + tree ind1 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg1)))); + tree ind2 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg2)))); + tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2)); + return expand_expr (result, target, mode, EXPAND_NORMAL); + } - /* Stabilize the arguments in case gen_cmpstr(n)si fail. */ - arg1 = builtin_save_expr (arg1); - arg2 = builtin_save_expr (arg2); +#ifdef HAVE_cmpstrsi + if (HAVE_cmpstrsi) + { + tree len, len1, len2; + rtx arg1_rtx, arg2_rtx, arg3_rtx; + rtx result, insn; + tree fndecl; - arg1_rtx = get_memory_rtx (arg1, NULL); - arg2_rtx = get_memory_rtx (arg2, NULL); + int arg1_align + = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + int arg2_align + = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + enum machine_mode insn_mode + = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; -#ifdef HAVE_cmpstrsi - /* Try to call cmpstrsi. */ - if (HAVE_cmpstrsi) - { - enum machine_mode insn_mode - = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; - - /* Make a place to write the result of the instruction. */ - result = target; - if (! (result != 0 - && REG_P (result) && GET_MODE (result) == insn_mode - && REGNO (result) >= FIRST_PSEUDO_REGISTER)) - result = gen_reg_rtx (insn_mode); - - insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, - GEN_INT (MIN (arg1_align, arg2_align))); - } -#endif -#ifdef HAVE_cmpstrnsi - /* Try to determine at least one length and call cmpstrnsi. */ - if (!insn && HAVE_cmpstrnsi) - { - tree len; - rtx arg3_rtx; - - enum machine_mode insn_mode - = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode; - tree len1 = c_strlen (arg1, 1); - tree len2 = c_strlen (arg2, 1); - - if (len1) - len1 = size_binop (PLUS_EXPR, ssize_int (1), len1); - if (len2) - len2 = size_binop (PLUS_EXPR, ssize_int (1), len2); - - /* If we don't have a constant length for the first, use the length - of the second, if we know it. We don't require a constant for - this case; some cost analysis could be done if both are available - but neither is constant. For now, assume they're equally cheap, - unless one has side effects. If both strings have constant lengths, - use the smaller. */ - - if (!len1) - len = len2; - else if (!len2) - len = len1; - else if (TREE_SIDE_EFFECTS (len1)) - len = len2; - else if (TREE_SIDE_EFFECTS (len2)) - len = len1; - else if (TREE_CODE (len1) != INTEGER_CST) - len = len2; - else if (TREE_CODE (len2) != INTEGER_CST) - len = len1; - else if (tree_int_cst_lt (len1, len2)) - len = len1; - else - len = len2; + len1 = c_strlen (arg1, 1); + len2 = c_strlen (arg2, 1); - /* If both arguments have side effects, we cannot optimize. */ - if (!len || TREE_SIDE_EFFECTS (len)) - goto do_libcall; + if (len1) + len1 = size_binop (PLUS_EXPR, ssize_int (1), len1); + if (len2) + len2 = size_binop (PLUS_EXPR, ssize_int (1), len2); - arg3_rtx = expand_normal (len); + /* If we don't have a constant length for the first, use the length + of the second, if we know it. We don't require a constant for + this case; some cost analysis could be done if both are available + but neither is constant. For now, assume they're equally cheap, + unless one has side effects. If both strings have constant lengths, + use the smaller. */ - /* Make a place to write the result of the instruction. */ - result = target; - if (! (result != 0 - && REG_P (result) && GET_MODE (result) == insn_mode - && REGNO (result) >= FIRST_PSEUDO_REGISTER)) - result = gen_reg_rtx (insn_mode); + if (!len1) + len = len2; + else if (!len2) + len = len1; + else if (TREE_SIDE_EFFECTS (len1)) + len = len2; + else if (TREE_SIDE_EFFECTS (len2)) + len = len1; + else if (TREE_CODE (len1) != INTEGER_CST) + len = len2; + else if (TREE_CODE (len2) != INTEGER_CST) + len = len1; + else if (tree_int_cst_lt (len1, len2)) + len = len1; + else + len = len2; - insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx, - GEN_INT (MIN (arg1_align, arg2_align))); - } -#endif + /* If both arguments have side effects, we cannot optimize. */ + if (!len || TREE_SIDE_EFFECTS (len)) + return 0; - if (insn) - { - emit_insn (insn); - - /* Return the value in the proper mode for this function. */ - mode = TYPE_MODE (TREE_TYPE (exp)); - if (GET_MODE (result) == mode) - return result; - if (target == 0) - return convert_to_mode (mode, result, 0); - convert_move (target, result, 0); - return target; - } + /* If we don't have POINTER_TYPE, call the function. */ + if (arg1_align == 0 || arg2_align == 0) + return 0; - /* Expand the library call ourselves using a stabilized argument - list to avoid re-evaluating the function's arguments twice. */ -#ifdef HAVE_cmpstrnsi - do_libcall: -#endif - arglist = build_tree_list (NULL_TREE, arg2); - arglist = tree_cons (NULL_TREE, arg1, arglist); - fndecl = get_callee_fndecl (exp); - fn = build_function_call_expr (fndecl, arglist); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); - return expand_call (fn, target, target == const0_rtx); - } + /* Make a place to write the result of the instruction. */ + result = target; + if (! (result != 0 + && GET_CODE (result) == REG && GET_MODE (result) == insn_mode + && REGNO (result) >= FIRST_PSEUDO_REGISTER)) + result = gen_reg_rtx (insn_mode); + + /* Stabilize the arguments in case gen_cmpstrsi fails. */ + arg1 = save_expr (arg1); + arg2 = save_expr (arg2); + + arg1_rtx = get_memory_rtx (arg1); + arg2_rtx = get_memory_rtx (arg2); + arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); + insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx, + GEN_INT (MIN (arg1_align, arg2_align))); + if (insn) + { + emit_insn (insn); + + /* Return the value in the proper mode for this function. */ + mode = TYPE_MODE (TREE_TYPE (exp)); + if (GET_MODE (result) == mode) + return result; + if (target == 0) + return convert_to_mode (mode, result, 0); + convert_move (target, result, 0); + return target; + } + + /* Expand the library call ourselves using a stabilized argument + list to avoid re-evaluating the function's arguments twice. */ + arglist = build_tree_list (NULL_TREE, arg2); + arglist = tree_cons (NULL_TREE, arg1, arglist); + fndecl = get_callee_fndecl (exp); + exp = build_function_call_expr (fndecl, arglist); + return expand_call (exp, target, target == const0_rtx); + } #endif return 0; } @@ -3823,37 +3413,83 @@ static rtx expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) { tree arglist = TREE_OPERAND (exp, 1); + tree arg1, arg2, arg3; + const char *p1, *p2; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; - else + + arg1 = TREE_VALUE (arglist); + arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + + /* If the len parameter is zero, return zero. */ + if (integer_zerop (arg3)) + { + /* Evaluate and ignore arg1 and arg2 in case they have + side-effects. */ + expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL); + expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL); + return const0_rtx; + } + + /* If arg1 and arg2 are equal (and not volatile), return zero. */ + if (operand_equal_p (arg1, arg2, 0)) + { + /* Evaluate and ignore arg3 in case it has side-effects. */ + expand_expr (arg3, const0_rtx, VOIDmode, EXPAND_NORMAL); + return const0_rtx; + } + + p1 = c_getstr (arg1); + p2 = c_getstr (arg2); + + /* If all arguments are constant, evaluate at compile-time. */ + if (host_integerp (arg3, 1) && p1 && p2) + { + const int r = strncmp (p1, p2, tree_low_cst (arg3, 1)); + return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx)); + } + + /* If len == 1 or (either string parameter is "" and (len >= 1)), + return (*(const u_char*)arg1 - *(const u_char*)arg2). */ + if (host_integerp (arg3, 1) + && (tree_low_cst (arg3, 1) == 1 + || (tree_low_cst (arg3, 1) > 1 + && ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))))) { - tree result = fold_builtin_strncmp (arglist); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); + tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); + tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node); + tree ind1 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg1)))); + tree ind2 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg2)))); + tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2)); + return expand_expr (result, target, mode, EXPAND_NORMAL); } /* If c_strlen can determine an expression for one of the string - lengths, and it doesn't have side effects, then emit cmpstrnsi + lengths, and it doesn't have side effects, then emit cmpstrsi using length MIN(strlen(string)+1, arg3). */ -#ifdef HAVE_cmpstrnsi - if (HAVE_cmpstrnsi) +#ifdef HAVE_cmpstrsi + if (HAVE_cmpstrsi) { - tree arg1 = TREE_VALUE (arglist); - tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); - tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); tree len, len1, len2; rtx arg1_rtx, arg2_rtx, arg3_rtx; rtx result, insn; - tree fndecl, fn; + tree fndecl; int arg1_align = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; int arg2_align = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; enum machine_mode insn_mode - = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode; + = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; len1 = c_strlen (arg1, 1); len2 = c_strlen (arg2, 1); @@ -3892,8 +3528,7 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) return 0; /* The actual new length parameter is MIN(len,arg3). */ - len = fold_build2 (MIN_EXPR, TREE_TYPE (len), len, - fold_convert (TREE_TYPE (len), arg3)); + len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3)); /* If we don't have POINTER_TYPE, call the function. */ if (arg1_align == 0 || arg2_align == 0) @@ -3902,20 +3537,20 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) /* Make a place to write the result of the instruction. */ result = target; if (! (result != 0 - && REG_P (result) && GET_MODE (result) == insn_mode + && GET_CODE (result) == REG && GET_MODE (result) == insn_mode && REGNO (result) >= FIRST_PSEUDO_REGISTER)) result = gen_reg_rtx (insn_mode); - /* Stabilize the arguments in case gen_cmpstrnsi fails. */ - arg1 = builtin_save_expr (arg1); - arg2 = builtin_save_expr (arg2); - len = builtin_save_expr (len); + /* Stabilize the arguments in case gen_cmpstrsi fails. */ + arg1 = save_expr (arg1); + arg2 = save_expr (arg2); + len = save_expr (len); - arg1_rtx = get_memory_rtx (arg1, len); - arg2_rtx = get_memory_rtx (arg2, len); - arg3_rtx = expand_normal (len); - insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx, - GEN_INT (MIN (arg1_align, arg2_align))); + arg1_rtx = get_memory_rtx (arg1); + arg2_rtx = get_memory_rtx (arg2); + arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); + insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx, + GEN_INT (MIN (arg1_align, arg2_align))); if (insn) { emit_insn (insn); @@ -3936,10 +3571,8 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) arglist = tree_cons (NULL_TREE, arg2, arglist); arglist = tree_cons (NULL_TREE, arg1, arglist); fndecl = get_callee_fndecl (exp); - fn = build_function_call_expr (fndecl, arglist); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); - return expand_call (fn, target, target == const0_rtx); + exp = build_function_call_expr (fndecl, arglist); + return expand_call (exp, target, target == const0_rtx); } #endif return 0; @@ -3950,61 +3583,61 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) otherwise try to get the result in TARGET, if convenient. */ static rtx -expand_builtin_strcat (tree fndecl, tree arglist, rtx target, enum machine_mode mode) +expand_builtin_strcat (tree arglist, rtx target, enum machine_mode mode) { if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; else { tree dst = TREE_VALUE (arglist), - src = TREE_VALUE (TREE_CHAIN (arglist)); + src = TREE_VALUE (TREE_CHAIN (arglist)); const char *p = c_getstr (src); - /* If the string length is zero, return the dst parameter. */ - if (p && *p == '\0') - return expand_expr (dst, target, mode, EXPAND_NORMAL); - - if (!optimize_size) + if (p) { - /* See if we can store by pieces into (dst + strlen(dst)). */ - tree newsrc, newdst, - strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN]; - rtx insns; - - /* Stabilize the argument list. */ - newsrc = builtin_save_expr (src); - if (newsrc != src) - arglist = build_tree_list (NULL_TREE, newsrc); - else - arglist = TREE_CHAIN (arglist); /* Reusing arglist if safe. */ - - dst = builtin_save_expr (dst); - - start_sequence (); - - /* Create strlen (dst). */ - newdst = - build_function_call_expr (strlen_fn, - build_tree_list (NULL_TREE, dst)); - /* Create (dst + (cast) strlen (dst)). */ - newdst = fold_convert (TREE_TYPE (dst), newdst); - newdst = fold_build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst); - - newdst = builtin_save_expr (newdst); - arglist = tree_cons (NULL_TREE, newdst, arglist); - - if (!expand_builtin_strcpy (fndecl, arglist, target, mode)) + /* If the string length is zero, return the dst parameter. */ + if (*p == '\0') + return expand_expr (dst, target, mode, EXPAND_NORMAL); + else if (!optimize_size) { - end_sequence (); /* Stop sequence. */ - return 0; + /* Otherwise if !optimize_size, see if we can store by + pieces into (dst + strlen(dst)). */ + tree newdst, arglist, + strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN]; + + /* This is the length argument. */ + arglist = build_tree_list (NULL_TREE, + fold (size_binop (PLUS_EXPR, + c_strlen (src, 0), + ssize_int (1)))); + /* Prepend src argument. */ + arglist = tree_cons (NULL_TREE, src, arglist); + + /* We're going to use dst more than once. */ + dst = save_expr (dst); + + /* Create strlen (dst). */ + newdst = + fold (build_function_call_expr (strlen_fn, + build_tree_list (NULL_TREE, + dst))); + /* Create (dst + strlen (dst)). */ + newdst = fold (build (PLUS_EXPR, TREE_TYPE (dst), dst, newdst)); + + /* Prepend the new dst argument. */ + arglist = tree_cons (NULL_TREE, newdst, arglist); + + /* We don't want to get turned into a memcpy if the + target is const0_rtx, i.e. when the return value + isn't used. That would produce pessimized code so + pass in a target of zero, it should never actually be + used. If this was successful return the original + dst, not the result of mempcpy. */ + if (expand_builtin_mempcpy (arglist, /*target=*/0, mode, /*endp=*/0)) + return expand_expr (dst, target, mode, EXPAND_NORMAL); + else + return 0; } - - /* Output the entire sequence. */ - insns = get_insns (); - end_sequence (); - emit_insn (insns); - - return expand_expr (dst, target, mode, EXPAND_NORMAL); } return 0; @@ -4018,14 +3651,46 @@ expand_builtin_strcat (tree fndecl, tree arglist, rtx target, enum machine_mode static rtx expand_builtin_strncat (tree arglist, rtx target, enum machine_mode mode) { - if (validate_arglist (arglist, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, + POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return 0; + else { - tree result = fold_builtin_strncat (arglist); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); + tree dst = TREE_VALUE (arglist), + src = TREE_VALUE (TREE_CHAIN (arglist)), + len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + const char *p = c_getstr (src); + + /* If the requested length is zero, or the src parameter string + length is zero, return the dst parameter. */ + if (integer_zerop (len) || (p && *p == '\0')) + { + /* Evaluate and ignore the src and len parameters in case + they have side-effects. */ + expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL); + expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (dst, target, mode, EXPAND_NORMAL); + } + + /* If the requested len is greater than or equal to the string + length, call strcat. */ + if (TREE_CODE (len) == INTEGER_CST && p + && compare_tree_int (len, strlen (p)) >= 0) + { + tree newarglist + = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src)); + tree fn = implicit_built_in_decls[BUILT_IN_STRCAT]; + + /* If the replacement _DECL isn't initialized, don't do the + transformation. */ + if (!fn) + return 0; + + return expand_expr (build_function_call_expr (fn, newarglist), + target, mode, EXPAND_NORMAL); + } + return 0; } - return 0; } /* Expand expression EXP, which is a call to the strspn builtin. @@ -4035,13 +3700,31 @@ expand_builtin_strncat (tree arglist, rtx target, enum machine_mode mode) static rtx expand_builtin_strspn (tree arglist, rtx target, enum machine_mode mode) { - if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + else { - tree result = fold_builtin_strspn (arglist); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + const char *p1 = c_getstr (s1), *p2 = c_getstr (s2); + + /* If both arguments are constants, evaluate at compile-time. */ + if (p1 && p2) + { + const size_t r = strspn (p1, p2); + return expand_expr (size_int (r), target, mode, EXPAND_NORMAL); + } + + /* If either argument is "", return 0. */ + if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')) + { + /* Evaluate and ignore both arguments in case either one has + side-effects. */ + expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL); + expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL); + return const0_rtx; + } + return 0; } - return 0; } /* Expand expression EXP, which is a call to the strcspn builtin. @@ -4051,13 +3734,45 @@ expand_builtin_strspn (tree arglist, rtx target, enum machine_mode mode) static rtx expand_builtin_strcspn (tree arglist, rtx target, enum machine_mode mode) { - if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + else { - tree result = fold_builtin_strcspn (arglist); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + const char *p1 = c_getstr (s1), *p2 = c_getstr (s2); + + /* If both arguments are constants, evaluate at compile-time. */ + if (p1 && p2) + { + const size_t r = strcspn (p1, p2); + return expand_expr (size_int (r), target, mode, EXPAND_NORMAL); + } + + /* If the first argument is "", return 0. */ + if (p1 && *p1 == '\0') + { + /* Evaluate and ignore argument s2 in case it has + side-effects. */ + expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL); + return const0_rtx; + } + + /* If the second argument is "", return __builtin_strlen(s1). */ + if (p2 && *p2 == '\0') + { + tree newarglist = build_tree_list (NULL_TREE, s1), + fn = implicit_built_in_decls[BUILT_IN_STRLEN]; + + /* If the replacement _DECL isn't initialized, don't do the + transformation. */ + if (!fn) + return 0; + + return expand_expr (build_function_call_expr (fn, newarglist), + target, mode, EXPAND_NORMAL); + } + return 0; } - return 0; } /* Expand a call to __builtin_saveregs, generating the result in TARGET, @@ -4091,7 +3806,7 @@ expand_builtin_saveregs (void) is inside a start_sequence, make the outer-level insn chain current, so the code is placed at the start of the function. */ push_topmost_sequence (); - emit_insn_after (seq, entry_of_function ()); + emit_insn_after (seq, get_insns ()); pop_topmost_sequence (); return val; @@ -4107,35 +3822,66 @@ expand_builtin_args_info (tree arglist) int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int); int *word_ptr = (int *) ¤t_function_args_info; - gcc_assert (sizeof (CUMULATIVE_ARGS) % sizeof (int) == 0); + if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0) + abort (); if (arglist != 0) { if (!host_integerp (TREE_VALUE (arglist), 0)) - error ("argument of %<__builtin_args_info%> must be constant"); + error ("argument of `__builtin_args_info' must be constant"); else { HOST_WIDE_INT wordnum = tree_low_cst (TREE_VALUE (arglist), 0); if (wordnum < 0 || wordnum >= nwords) - error ("argument of %<__builtin_args_info%> out of range"); + error ("argument of `__builtin_args_info' out of range"); else return GEN_INT (word_ptr[wordnum]); } } else - error ("missing argument in %<__builtin_args_info%>"); + error ("missing argument in `__builtin_args_info'"); return const0_rtx; } -/* Expand a call to __builtin_next_arg. */ +/* Expand ARGLIST, from a call to __builtin_next_arg. */ static rtx -expand_builtin_next_arg (void) +expand_builtin_next_arg (tree arglist) { - /* Checking arguments is already done in fold_builtin_next_arg - that must be called before this function. */ + tree fntype = TREE_TYPE (current_function_decl); + + if (TYPE_ARG_TYPES (fntype) == 0 + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + == void_type_node)) + { + error ("`va_start' used in function with fixed args"); + return const0_rtx; + } + + if (arglist) + { + tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl)); + tree arg = TREE_VALUE (arglist); + + /* Strip off all nops for the sake of the comparison. This + is not quite the same as STRIP_NOPS. It does more. + We must also strip off INDIRECT_EXPR for C++ reference + parameters. */ + while (TREE_CODE (arg) == NOP_EXPR + || TREE_CODE (arg) == CONVERT_EXPR + || TREE_CODE (arg) == NON_LVALUE_EXPR + || TREE_CODE (arg) == INDIRECT_REF) + arg = TREE_OPERAND (arg, 0); + if (arg != last_parm) + warning ("second parameter of `va_start' not last named argument"); + } + else + /* Evidently an out of date version of <stdarg.h>; can't validate + va_start's second argument, but can still work as intended. */ + warning ("`__builtin_next_arg' called without an argument"); + return expand_binop (Pmode, add_optab, current_function_internal_arg_pointer, current_function_arg_offset_rtx, @@ -4160,7 +3906,10 @@ stabilize_va_list (tree valist, int needs_lvalue) if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE) { tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node)); - valist = build_fold_addr_expr_with_type (valist, p1); + tree p2 = build_pointer_type (va_list_type_node); + + valist = build1 (ADDR_EXPR, p2, valist); + valist = fold (build1 (NOP_EXPR, p1, valist)); } } else @@ -4173,13 +3922,14 @@ stabilize_va_list (tree valist, int needs_lvalue) return valist; pt = build_pointer_type (va_list_type_node); - valist = fold_build1 (ADDR_EXPR, pt, valist); + valist = fold (build1 (ADDR_EXPR, pt, valist)); TREE_SIDE_EFFECTS (valist) = 1; } if (TREE_SIDE_EFFECTS (valist)) valist = save_expr (valist); - valist = build_fold_indirect_ref (valist); + valist = fold (build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), + valist)); } return valist; @@ -4201,8 +3951,8 @@ std_expand_builtin_va_start (tree valist, rtx nextarg) { tree t; - t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, - make_tree (ptr_type_node, nextarg)); + t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, + make_tree (ptr_type_node, nextarg)); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); @@ -4218,16 +3968,10 @@ expand_builtin_va_start (tree arglist) chain = TREE_CHAIN (arglist); - if (!chain) - { - error ("too few arguments to function %<va_start%>"); - return const0_rtx; - } + if (TREE_CHAIN (chain)) + error ("too many arguments to function `va_start'"); - if (fold_builtin_next_arg (chain)) - return const0_rtx; - - nextarg = expand_builtin_next_arg (); + nextarg = expand_builtin_next_arg (chain); valist = stabilize_va_list (TREE_VALUE (arglist), 1); #ifdef EXPAND_BUILTIN_VA_START @@ -4242,211 +3986,180 @@ expand_builtin_va_start (tree arglist) /* The "standard" implementation of va_arg: read the value from the current (padded) address and increment by the (padded) size. */ -tree -std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p) +rtx +std_expand_builtin_va_arg (tree valist, tree type) { - tree addr, t, type_size, rounded_size, valist_tmp; - unsigned HOST_WIDE_INT align, boundary; - bool indirect; - -#ifdef ARGS_GROW_DOWNWARD - /* All of the alignment and movement below is for args-grow-up machines. - As of 2004, there are only 3 ARGS_GROW_DOWNWARD targets, and they all - implement their own specialized gimplify_va_arg_expr routines. */ - gcc_unreachable (); -#endif - - indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false); - if (indirect) - type = build_pointer_type (type); - - align = PARM_BOUNDARY / BITS_PER_UNIT; - boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type) / BITS_PER_UNIT; + tree addr_tree, t, type_size = NULL; + tree align, alignm1; + tree rounded_size; + rtx addr; + HOST_WIDE_INT boundary; - /* Hoist the valist value into a temporary for the moment. */ - valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL); + /* Compute the rounded size of the type. */ + align = size_int (PARM_BOUNDARY / BITS_PER_UNIT); + alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1); + boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type); /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually requires greater alignment, we must perform dynamic alignment. */ - if (boundary > align - && !integer_zerop (TYPE_SIZE (type))) - { - t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1)); - t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp, - build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t)); - gimplify_and_add (t, pre_p); - - t = fold_convert (TREE_TYPE (valist), size_int (-boundary)); - t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp, - build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp, t)); - gimplify_and_add (t, pre_p); - } - else - boundary = align; - /* If the actual alignment is less than the alignment of the type, - adjust the type accordingly so that we don't assume strict alignment - when deferencing the pointer. */ - boundary *= BITS_PER_UNIT; - if (boundary < TYPE_ALIGN (type)) + if (boundary > PARM_BOUNDARY) { - type = build_variant_type_copy (type); - TYPE_ALIGN (type) = boundary; + if (!PAD_VARARGS_DOWN) + { + t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, + build (PLUS_EXPR, TREE_TYPE (valist), valist, + build_int_2 (boundary / BITS_PER_UNIT - 1, 0))); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + } + t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, + build (BIT_AND_EXPR, TREE_TYPE (valist), valist, + build_int_2 (~(boundary / BITS_PER_UNIT - 1), -1))); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } - - /* Compute the rounded size of the type. */ - type_size = size_in_bytes (type); - rounded_size = round_up (type_size, align); - - /* Reduce rounded_size so it's sharable with the postqueue. */ - gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue); + if (type == error_mark_node + || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL + || TREE_OVERFLOW (type_size)) + rounded_size = size_zero_node; + else + rounded_size = fold (build (MULT_EXPR, sizetype, + fold (build (TRUNC_DIV_EXPR, sizetype, + fold (build (PLUS_EXPR, sizetype, + type_size, alignm1)), + align)), + align)); /* Get AP. */ - addr = valist_tmp; - if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size)) + addr_tree = valist; + if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size)) { /* Small args are padded downward. */ - t = fold_build2 (GT_EXPR, sizetype, rounded_size, size_int (align)); - t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node, - size_binop (MINUS_EXPR, rounded_size, type_size)); - t = fold_convert (TREE_TYPE (addr), t); - addr = fold_build2 (PLUS_EXPR, TREE_TYPE (addr), addr, t); + addr_tree = fold (build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree, + fold (build (COND_EXPR, sizetype, + fold (build (GT_EXPR, sizetype, + rounded_size, + align)), + size_zero_node, + fold (build (MINUS_EXPR, sizetype, + rounded_size, + type_size)))))); } - /* Compute new value for AP. */ - t = fold_convert (TREE_TYPE (valist), rounded_size); - t = build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t); - t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t); - gimplify_and_add (t, pre_p); - - addr = fold_convert (build_pointer_type (type), addr); - - if (indirect) - addr = build_va_arg_indirect_ref (addr); - - return build_va_arg_indirect_ref (addr); -} + addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL); + addr = copy_to_reg (addr); -/* Build an indirect-ref expression over the given TREE, which represents a - piece of a va_arg() expansion. */ -tree -build_va_arg_indirect_ref (tree addr) -{ - addr = build_fold_indirect_ref (addr); - - if (flag_mudflap) /* Don't instrument va_arg INDIRECT_REF. */ - mf_mark (addr); + /* Compute new value for AP. */ + if (! integer_zerop (rounded_size)) + { + t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, + build (PLUS_EXPR, TREE_TYPE (valist), valist, + rounded_size)); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + } return addr; } -/* Return a dummy expression of type TYPE in order to keep going after an - error. */ +/* Expand __builtin_va_arg, which is not really a builtin function, but + a very special sort of operator. */ -static tree -dummy_object (tree type) -{ - tree t = build_int_cst (build_pointer_type (type), 0); - return build1 (INDIRECT_REF, type, t); -} - -/* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a - builtin function, but a very special sort of operator. */ - -enum gimplify_status -gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p) +rtx +expand_builtin_va_arg (tree valist, tree type) { + rtx addr, result; tree promoted_type, want_va_type, have_va_type; - tree valist = TREE_OPERAND (*expr_p, 0); - tree type = TREE_TYPE (*expr_p); - tree t; /* Verify that valist is of the proper type. */ + want_va_type = va_list_type_node; have_va_type = TREE_TYPE (valist); - - if (have_va_type == error_mark_node) - return GS_ERROR; - if (TREE_CODE (want_va_type) == ARRAY_TYPE) { /* If va_list is an array type, the argument may have decayed to a pointer type, e.g. by being passed to another function. - In that case, unwrap both types so that we can compare the + In that case, unwrap both types so that we can compare the underlying records. */ if (TREE_CODE (have_va_type) == ARRAY_TYPE - || POINTER_TYPE_P (have_va_type)) + || TREE_CODE (have_va_type) == POINTER_TYPE) { want_va_type = TREE_TYPE (want_va_type); have_va_type = TREE_TYPE (have_va_type); } } - if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type)) { - error ("first argument to %<va_arg%> not of type %<va_list%>"); - return GS_ERROR; + error ("first argument to `va_arg' not of type `va_list'"); + addr = const0_rtx; } /* Generate a diagnostic for requesting data of a type that cannot be passed through `...' due to type promotion at the call site. */ - else if ((promoted_type = lang_hooks.types.type_promotes_to (type)) + else if ((promoted_type = (*lang_hooks.types.type_promotes_to) (type)) != type) { + const char *name = "<anonymous type>", *pname = 0; static bool gave_help; + if (TYPE_NAME (type)) + { + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + name = IDENTIFIER_POINTER (TYPE_NAME (type)); + else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (type))) + name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); + } + if (TYPE_NAME (promoted_type)) + { + if (TREE_CODE (TYPE_NAME (promoted_type)) == IDENTIFIER_NODE) + pname = IDENTIFIER_POINTER (TYPE_NAME (promoted_type)); + else if (TREE_CODE (TYPE_NAME (promoted_type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (promoted_type))) + pname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (promoted_type))); + } + /* Unfortunately, this is merely undefined, rather than a constraint violation, so we cannot make this an error. If this call is never executed, the program is still strictly conforming. */ - warning (0, "%qT is promoted to %qT when passed through %<...%>", - type, promoted_type); + warning ("`%s' is promoted to `%s' when passed through `...'", + name, pname); if (! gave_help) { gave_help = true; - warning (0, "(so you should pass %qT not %qT to %<va_arg%>)", - promoted_type, type); + warning ("(so you should pass `%s' not `%s' to `va_arg')", + pname, name); } /* We can, however, treat "undefined" any way we please. Call abort to encourage the user to fix the program. */ inform ("if this code is reached, the program will abort"); - t = build_function_call_expr (implicit_built_in_decls[BUILT_IN_TRAP], - NULL); - append_to_statement_list (t, pre_p); + expand_builtin_trap (); /* This is dead code, but go ahead and finish so that the mode of the result comes out right. */ - *expr_p = dummy_object (type); - return GS_ALL_DONE; + addr = const0_rtx; } else { /* Make it easier for the backends by protecting the valist argument - from multiple evaluations. */ - if (TREE_CODE (va_list_type_node) == ARRAY_TYPE) - { - /* For this case, the backends will be expecting a pointer to - TREE_TYPE (va_list_type_node), but it's possible we've - actually been given an array (an actual va_list_type_node). - So fix it. */ - if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE) - { - tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node)); - valist = build_fold_addr_expr_with_type (valist, p1); - } - gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue); - } - else - gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue); + from multiple evaluations. */ + valist = stabilize_va_list (valist, 0); - if (!targetm.gimplify_va_arg_expr) - /* FIXME:Once most targets are converted we should merely - assert this is non-null. */ - return GS_ALL_DONE; - - *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p); - return GS_OK; +#ifdef EXPAND_BUILTIN_VA_ARG + addr = EXPAND_BUILTIN_VA_ARG (valist, type); +#else + addr = std_expand_builtin_va_arg (valist, type); +#endif } + + addr = convert_memory_address (Pmode, addr); + + result = gen_rtx_MEM (TYPE_MODE (type), addr); + set_mem_alias_set (result, get_varargs_alias_set ()); + + return result; } /* Expand ARGLIST, from a call to __builtin_va_end. */ @@ -4481,7 +4194,7 @@ expand_builtin_va_copy (tree arglist) if (TREE_CODE (va_list_type_node) != ARRAY_TYPE) { - t = build2 (MODIFY_EXPR, va_list_type_node, dst, src); + t = build (MODIFY_EXPR, va_list_type_node, dst, src); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } @@ -4528,24 +4241,25 @@ expand_builtin_frame_address (tree fndecl, tree arglist) else if (! host_integerp (TREE_VALUE (arglist), 1)) { if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) - error ("invalid argument to %<__builtin_frame_address%>"); + error ("invalid arg to `__builtin_frame_address'"); else - error ("invalid argument to %<__builtin_return_address%>"); + error ("invalid arg to `__builtin_return_address'"); return const0_rtx; } else { rtx tem = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl), - tree_low_cst (TREE_VALUE (arglist), 1)); + tree_low_cst (TREE_VALUE (arglist), 1), + hard_frame_pointer_rtx); /* Some ports cannot access arbitrary stack frames. */ if (tem == NULL) { if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) - warning (0, "unsupported argument to %<__builtin_frame_address%>"); + warning ("unsupported arg to `__builtin_frame_address'"); else - warning (0, "unsupported argument to %<__builtin_return_address%>"); + warning ("unsupported arg to `__builtin_return_address'"); return const0_rtx; } @@ -4553,7 +4267,7 @@ expand_builtin_frame_address (tree fndecl, tree arglist) if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) return tem; - if (!REG_P (tem) + if (GET_CODE (tem) != REG && ! CONSTANT_P (tem)) tem = copy_to_mode_reg (Pmode, tem); return tem; @@ -4570,17 +4284,11 @@ expand_builtin_alloca (tree arglist, rtx target) rtx op0; rtx result; - /* In -fmudflap-instrumented code, alloca() and __builtin_alloca() - should always expand to function calls. These can be intercepted - in libmudflap. */ - if (flag_mudflap) - return 0; - if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE)) return 0; /* Compute the argument. */ - op0 = expand_normal (TREE_VALUE (arglist)); + op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0); /* Allocate the desired space. */ result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT); @@ -4608,7 +4316,8 @@ expand_builtin_unop (enum machine_mode target_mode, tree arglist, rtx target, Set TARGET to wherever the result comes back. */ target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))), op_optab, op0, target, 1); - gcc_assert (target); + if (target == 0) + abort (); return convert_to_mode (target_mode, target, 0); } @@ -4619,15 +4328,83 @@ expand_builtin_unop (enum machine_mode target_mode, tree arglist, rtx target, static rtx expand_builtin_fputs (tree arglist, rtx target, bool unlocked) { + tree len, fn; + /* If we're using an unlocked function, assume the other unlocked + functions exist explicitly. */ + tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED] + : implicit_built_in_decls[BUILT_IN_FPUTC]; + tree const fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED] + : implicit_built_in_decls[BUILT_IN_FWRITE]; + + /* If the return value is used, don't do the transformation. */ + if (target != const0_rtx) + return 0; + /* Verify the arguments in the original call. */ - if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + + /* Get the length of the string passed to fputs. If the length + can't be determined, punt. */ + if (!(len = c_strlen (TREE_VALUE (arglist), 1)) + || TREE_CODE (len) != INTEGER_CST) + return 0; + + switch (compare_tree_int (len, 1)) { - tree result = fold_builtin_fputs (arglist, (target == const0_rtx), - unlocked, NULL_TREE); - if (result) - return expand_expr (result, target, VOIDmode, EXPAND_NORMAL); + case -1: /* length is 0, delete the call entirely . */ + { + /* Evaluate and ignore the argument in case it has + side-effects. */ + expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx, + VOIDmode, EXPAND_NORMAL); + return const0_rtx; + } + case 0: /* length is 1, call fputc. */ + { + const char *p = c_getstr (TREE_VALUE (arglist)); + + if (p != NULL) + { + /* New argument list transforming fputs(string, stream) to + fputc(string[0], stream). */ + arglist = + build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist))); + arglist = + tree_cons (NULL_TREE, build_int_2 (p[0], 0), arglist); + fn = fn_fputc; + break; + } + } + /* Fall through. */ + case 1: /* length is greater than 1, call fwrite. */ + { + tree string_arg; + + /* If optimizing for size keep fputs. */ + if (optimize_size) + return 0; + string_arg = TREE_VALUE (arglist); + /* New argument list transforming fputs(string, stream) to + fwrite(string, 1, len, stream). */ + arglist = build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist))); + arglist = tree_cons (NULL_TREE, len, arglist); + arglist = tree_cons (NULL_TREE, size_one_node, arglist); + arglist = tree_cons (NULL_TREE, string_arg, arglist); + fn = fn_fwrite; + break; + } + default: + abort (); } - return 0; + + /* If the replacement _DECL isn't initialized, don't do the + transformation. */ + if (!fn) + return 0; + + return expand_expr (build_function_call_expr (fn, arglist), + const0_rtx, VOIDmode, EXPAND_NORMAL); } /* Expand a call to __builtin_expect. We return our argument and emit a @@ -4648,7 +4425,7 @@ expand_builtin_expect (tree arglist, rtx target) if (TREE_CODE (c) != INTEGER_CST) { - error ("second argument to %<__builtin_expect%> must be a constant"); + error ("second arg to `__builtin_expect' must be a constant"); c = integer_zero_node; } @@ -4699,9 +4476,9 @@ expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label) ret = get_insns (); drop_through_label = get_last_insn (); - if (drop_through_label && NOTE_P (drop_through_label)) + if (drop_through_label && GET_CODE (drop_through_label) == NOTE) drop_through_label = prev_nonnote_insn (drop_through_label); - if (drop_through_label && !LABEL_P (drop_through_label)) + if (drop_through_label && GET_CODE (drop_through_label) != CODE_LABEL) drop_through_label = NULL_RTX; end_sequence (); @@ -4716,7 +4493,7 @@ expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label) { rtx next = NEXT_INSN (insn); - if (JUMP_P (insn) && any_condjump_p (insn)) + if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)) { rtx ifelse = SET_SRC (pc_set (insn)); rtx then_dest = XEXP (ifelse, 1); @@ -4739,10 +4516,10 @@ expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label) /* Otherwise check where we drop through. */ else if (else_dest == pc_rtx) { - if (next && NOTE_P (next)) + if (next && GET_CODE (next) == NOTE) next = next_nonnote_insn (next); - if (next && JUMP_P (next) + if (next && GET_CODE (next) == JUMP_INSN && any_uncondjump_p (next)) temp = XEXP (SET_SRC (pc_set (next)), 0); else @@ -4757,10 +4534,10 @@ expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label) } else if (then_dest == pc_rtx) { - if (next && NOTE_P (next)) + if (next && GET_CODE (next) == NOTE) next = next_nonnote_insn (next); - if (next && JUMP_P (next) + if (next && GET_CODE (next) == JUMP_INSN && any_uncondjump_p (next)) temp = XEXP (SET_SRC (pc_set (next)), 0); else @@ -4778,7 +4555,7 @@ expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label) probabilities. */ if (integer_zerop (arg1)) taken = 1 - taken; - predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken); + predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken); } } @@ -4823,43 +4600,43 @@ expand_builtin_fabs (tree arglist, rtx target, rtx subtarget) return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1)); } -/* Expand a call to copysign, copysignf, or copysignl with arguments ARGLIST. - Return NULL is a normal call should be emitted rather than expanding the - function inline. If convenient, the result should be placed in TARGET. - SUBTARGET may be used as the target for computing the operand. */ +/* Expand a call to cabs, cabsf or cabsl with arguments ARGLIST. + Return 0 if a normal call should be emitted rather than expanding + the function inline. If convenient, the result should be placed + in target. */ static rtx -expand_builtin_copysign (tree arglist, rtx target, rtx subtarget) +expand_builtin_cabs (tree arglist, rtx target) { - rtx op0, op1; + enum machine_mode mode; tree arg; + rtx op0; - if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) + if (arglist == 0 || TREE_CHAIN (arglist)) return 0; - arg = TREE_VALUE (arglist); - op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL); - - arg = TREE_VALUE (TREE_CHAIN (arglist)); - op1 = expand_normal (arg); + if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE + || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE) + return 0; - return expand_copysign (op0, op1, target); + mode = TYPE_MODE (TREE_TYPE (arg)); + op0 = expand_expr (arg, NULL_RTX, VOIDmode, 0); + return expand_complex_abs (mode, op0, target, 0); } /* Create a new constant string literal and return a char* pointer to it. The STRING_CST value is the LEN characters at STR. */ -tree +static tree build_string_literal (int len, const char *str) { tree t, elem, index, type; t = build_string (len, str); elem = build_type_variant (char_type_node, 1, 0); - index = build_index_type (build_int_cst (NULL_TREE, len - 1)); + index = build_index_type (build_int_2 (len - 1, 0)); type = build_array_type (elem, index); TREE_TYPE (t) = type; TREE_CONSTANT (t) = 1; - TREE_INVARIANT (t) = 1; TREE_READONLY (t) = 1; TREE_STATIC (t) = 1; @@ -4871,16 +4648,15 @@ build_string_literal (int len, const char *str) return t; } -/* Expand EXP, a call to printf or printf_unlocked. +/* Expand a call to printf or printf_unlocked with argument list ARGLIST. Return 0 if a normal call should be emitted rather than transforming the function inline. If convenient, the result should be placed in - TARGET with mode MODE. UNLOCKED indicates this is a printf_unlocked + TARGET with mode MODE. UNLOCKED indicates this is a printf_unlocked call. */ static rtx -expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, +expand_builtin_printf (tree arglist, rtx target, enum machine_mode mode, bool unlocked) { - tree arglist = TREE_OPERAND (exp, 1); /* If we're using an unlocked function, assume the other unlocked functions exist explicitly. */ tree const fn_putchar = unlocked ? built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED] @@ -4898,7 +4674,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, if (! arglist) return 0; fmt = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (fmt))) + if (TREE_CODE (TREE_TYPE (fmt)) != POINTER_TYPE) return 0; arglist = TREE_CHAIN (arglist); @@ -4907,20 +4683,17 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, if (fmt_str == NULL) return 0; - if (!init_target_chars()) - return 0; - /* If the format specifier was "%s\n", call __builtin_puts(arg). */ - if (strcmp (fmt_str, target_percent_s_newline) == 0) + if (strcmp (fmt_str, "%s\n") == 0) { if (! arglist - || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))) + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE || TREE_CHAIN (arglist)) return 0; fn = fn_puts; } /* If the format specifier was "%c", call __builtin_putchar(arg). */ - else if (strcmp (fmt_str, target_percent_c) == 0) + else if (strcmp (fmt_str, "%c") == 0) { if (! arglist || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE @@ -4931,8 +4704,8 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, else { /* We can't handle anything else with % args or %% ... yet. */ - if (strchr (fmt_str, target_percent)) - return 0; + if (strchr (fmt_str, '%')) + return 0; if (arglist) return 0; @@ -4946,7 +4719,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, /* Given printf("c"), (where c is any one character,) convert "c"[0] to an int and pass that to the replacement function. */ - arg = build_int_cst (NULL_TREE, fmt_str[0]); + arg = build_int_2 (fmt_str[0], 0); arglist = build_tree_list (NULL_TREE, arg); fn = fn_putchar; } @@ -4954,11 +4727,11 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, { /* If the format specifier was "string\n", call puts("string"). */ size_t len = strlen (fmt_str); - if ((unsigned char)fmt_str[len - 1] == target_newline) + if (fmt_str[len - 1] == '\n') { /* Create a NUL-terminated string that's one char shorter than the original, stripping off the trailing '\n'. */ - char *newstr = alloca (len); + char *newstr = (char *) alloca (len); memcpy (newstr, fmt_str, len - 1); newstr[len - 1] = 0; @@ -4975,22 +4748,19 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, if (!fn) return 0; - fn = build_function_call_expr (fn, arglist); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); - return expand_expr (fn, target, mode, EXPAND_NORMAL); + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } -/* Expand EXP, a call to fprintf or fprintf_unlocked. +/* Expand a call to fprintf or fprintf_unlocked with argument list ARGLIST. Return 0 if a normal call should be emitted rather than transforming the function inline. If convenient, the result should be placed in - TARGET with mode MODE. UNLOCKED indicates this is a fprintf_unlocked + TARGET with mode MODE. UNLOCKED indicates this is a fprintf_unlocked call. */ static rtx -expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, - bool unlocked) +expand_builtin_fprintf (tree arglist, rtx target, enum machine_mode mode, + bool unlocked) { - tree arglist = TREE_OPERAND (exp, 1); /* If we're using an unlocked function, assume the other unlocked functions exist explicitly. */ tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED] @@ -5008,13 +4778,13 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, if (! arglist) return 0; fp = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (fp))) + if (TREE_CODE (TREE_TYPE (fp)) != POINTER_TYPE) return 0; arglist = TREE_CHAIN (arglist); if (! arglist) return 0; fmt = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (fmt))) + if (TREE_CODE (TREE_TYPE (fmt)) != POINTER_TYPE) return 0; arglist = TREE_CHAIN (arglist); @@ -5023,14 +4793,11 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, if (fmt_str == NULL) return 0; - if (!init_target_chars()) - return 0; - /* If the format specifier was "%s", call __builtin_fputs(arg,fp). */ - if (strcmp (fmt_str, target_percent_s) == 0) + if (strcmp (fmt_str, "%s") == 0) { if (! arglist - || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))) + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE || TREE_CHAIN (arglist)) return 0; arg = TREE_VALUE (arglist); @@ -5039,7 +4806,7 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, fn = fn_fputs; } /* If the format specifier was "%c", call __builtin_fputc(arg,fp). */ - else if (strcmp (fmt_str, target_percent_c) == 0) + else if (strcmp (fmt_str, "%c") == 0) { if (! arglist || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE @@ -5053,8 +4820,8 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, else { /* We can't handle anything else with % args or %% ... yet. */ - if (strchr (fmt_str, target_percent)) - return 0; + if (strchr (fmt_str, '%')) + return 0; if (arglist) return 0; @@ -5077,10 +4844,8 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, if (!fn) return 0; - fn = build_function_call_expr (fn, arglist); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); - return expand_expr (fn, target, mode, EXPAND_NORMAL); + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } /* Expand a call to sprintf with argument list ARGLIST. Return 0 if @@ -5100,13 +4865,13 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) if (! arglist) return 0; dest = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (dest))) + if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE) return 0; arglist = TREE_CHAIN (arglist); if (! arglist) return 0; fmt = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (fmt))) + if (TREE_CODE (TREE_TYPE (fmt)) != POINTER_TYPE) return 0; arglist = TREE_CHAIN (arglist); @@ -5115,11 +4880,8 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) if (fmt_str == NULL) return 0; - if (!init_target_chars()) - return 0; - /* If the format doesn't contain % args or %%, use strcpy. */ - if (strchr (fmt_str, target_percent) == 0) + if (strchr (fmt_str, '%') == 0) { tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; tree exp; @@ -5130,11 +4892,12 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) const0_rtx, VOIDmode, EXPAND_NORMAL); if (target == const0_rtx) return const0_rtx; - exp = build_int_cst (NULL_TREE, strlen (fmt_str)); + exp = build_int_2 (strlen (fmt_str), 0); + exp = fold (build1 (NOP_EXPR, integer_type_node, exp)); return expand_expr (exp, target, mode, EXPAND_NORMAL); } /* If the format is "%s", use strcpy if the result isn't used. */ - else if (strcmp (fmt_str, target_percent_s) == 0) + else if (strcmp (fmt_str, "%s") == 0) { tree fn, arg, len; fn = implicit_built_in_decls[BUILT_IN_STRCPY]; @@ -5145,7 +4908,7 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) if (! arglist || TREE_CHAIN (arglist)) return 0; arg = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (arg))) + if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE) return 0; if (target != const0_rtx) @@ -5169,472 +4932,6 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) return 0; } - -/* Expand a call to either the entry or exit function profiler. */ - -static rtx -expand_builtin_profile_func (bool exitp) -{ - rtx this, which; - - this = DECL_RTL (current_function_decl); - gcc_assert (MEM_P (this)); - this = XEXP (this, 0); - - if (exitp) - which = profile_function_exit_libfunc; - else - which = profile_function_entry_libfunc; - - emit_library_call (which, LCT_NORMAL, VOIDmode, 2, this, Pmode, - expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, - 0), - Pmode); - - return const0_rtx; -} - -/* Given a trampoline address, make sure it satisfies TRAMPOLINE_ALIGNMENT. */ - -static rtx -round_trampoline_addr (rtx tramp) -{ - rtx temp, addend, mask; - - /* If we don't need too much alignment, we'll have been guaranteed - proper alignment by get_trampoline_type. */ - if (TRAMPOLINE_ALIGNMENT <= STACK_BOUNDARY) - return tramp; - - /* Round address up to desired boundary. */ - temp = gen_reg_rtx (Pmode); - addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1); - mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT); - - temp = expand_simple_binop (Pmode, PLUS, tramp, addend, - temp, 0, OPTAB_LIB_WIDEN); - tramp = expand_simple_binop (Pmode, AND, temp, mask, - temp, 0, OPTAB_LIB_WIDEN); - - return tramp; -} - -static rtx -expand_builtin_init_trampoline (tree arglist) -{ - tree t_tramp, t_func, t_chain; - rtx r_tramp, r_func, r_chain; -#ifdef TRAMPOLINE_TEMPLATE - rtx blktramp; -#endif - - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, - POINTER_TYPE, VOID_TYPE)) - return NULL_RTX; - - t_tramp = TREE_VALUE (arglist); - arglist = TREE_CHAIN (arglist); - t_func = TREE_VALUE (arglist); - arglist = TREE_CHAIN (arglist); - t_chain = TREE_VALUE (arglist); - - r_tramp = expand_normal (t_tramp); - r_func = expand_normal (t_func); - r_chain = expand_normal (t_chain); - - /* Generate insns to initialize the trampoline. */ - r_tramp = round_trampoline_addr (r_tramp); -#ifdef TRAMPOLINE_TEMPLATE - blktramp = gen_rtx_MEM (BLKmode, r_tramp); - set_mem_align (blktramp, TRAMPOLINE_ALIGNMENT); - emit_block_move (blktramp, assemble_trampoline_template (), - GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); -#endif - trampolines_created = 1; - INITIALIZE_TRAMPOLINE (r_tramp, r_func, r_chain); - - return const0_rtx; -} - -static rtx -expand_builtin_adjust_trampoline (tree arglist) -{ - rtx tramp; - - if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) - return NULL_RTX; - - tramp = expand_normal (TREE_VALUE (arglist)); - tramp = round_trampoline_addr (tramp); -#ifdef TRAMPOLINE_ADJUST_ADDRESS - TRAMPOLINE_ADJUST_ADDRESS (tramp); -#endif - - return tramp; -} - -/* Expand a call to the built-in signbit, signbitf or signbitl function. - Return NULL_RTX if a normal call should be emitted rather than expanding - the function in-line. EXP is the expression that is a call to the builtin - function; if convenient, the result should be placed in TARGET. */ - -static rtx -expand_builtin_signbit (tree exp, rtx target) -{ - const struct real_format *fmt; - enum machine_mode fmode, imode, rmode; - HOST_WIDE_INT hi, lo; - tree arg, arglist; - int word, bitpos; - rtx temp; - - arglist = TREE_OPERAND (exp, 1); - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return 0; - - arg = TREE_VALUE (arglist); - fmode = TYPE_MODE (TREE_TYPE (arg)); - rmode = TYPE_MODE (TREE_TYPE (exp)); - fmt = REAL_MODE_FORMAT (fmode); - - /* For floating point formats without a sign bit, implement signbit - as "ARG < 0.0". */ - bitpos = fmt->signbit_ro; - if (bitpos < 0) - { - /* But we can't do this if the format supports signed zero. */ - if (fmt->has_signed_zero && HONOR_SIGNED_ZEROS (fmode)) - return 0; - - arg = fold_build2 (LT_EXPR, TREE_TYPE (exp), arg, - build_real (TREE_TYPE (arg), dconst0)); - return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL); - } - - temp = expand_normal (arg); - if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD) - { - imode = int_mode_for_mode (fmode); - if (imode == BLKmode) - return 0; - temp = gen_lowpart (imode, temp); - } - else - { - imode = word_mode; - /* Handle targets with different FP word orders. */ - if (FLOAT_WORDS_BIG_ENDIAN) - word = (GET_MODE_BITSIZE (fmode) - bitpos) / BITS_PER_WORD; - else - word = bitpos / BITS_PER_WORD; - temp = operand_subword_force (temp, word, fmode); - bitpos = bitpos % BITS_PER_WORD; - } - - /* Force the intermediate word_mode (or narrower) result into a - register. This avoids attempting to create paradoxical SUBREGs - of floating point modes below. */ - temp = force_reg (imode, temp); - - /* If the bitpos is within the "result mode" lowpart, the operation - can be implement with a single bitwise AND. Otherwise, we need - a right shift and an AND. */ - - if (bitpos < GET_MODE_BITSIZE (rmode)) - { - if (bitpos < HOST_BITS_PER_WIDE_INT) - { - hi = 0; - lo = (HOST_WIDE_INT) 1 << bitpos; - } - else - { - hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT); - lo = 0; - } - - if (imode != rmode) - temp = gen_lowpart (rmode, temp); - temp = expand_binop (rmode, and_optab, temp, - immed_double_const (lo, hi, rmode), - NULL_RTX, 1, OPTAB_LIB_WIDEN); - } - else - { - /* Perform a logical right shift to place the signbit in the least - significant bit, then truncate the result to the desired mode - and mask just this bit. */ - temp = expand_shift (RSHIFT_EXPR, imode, temp, - build_int_cst (NULL_TREE, bitpos), NULL_RTX, 1); - temp = gen_lowpart (rmode, temp); - temp = expand_binop (rmode, and_optab, temp, const1_rtx, - NULL_RTX, 1, OPTAB_LIB_WIDEN); - } - - return temp; -} - -/* Expand fork or exec calls. TARGET is the desired target of the - call. ARGLIST is the list of arguments of the call. FN is the - identificator of the actual function. IGNORE is nonzero if the - value is to be ignored. */ - -static rtx -expand_builtin_fork_or_exec (tree fn, tree arglist, rtx target, int ignore) -{ - tree id, decl; - tree call; - - /* If we are not profiling, just call the function. */ - if (!profile_arc_flag) - return NULL_RTX; - - /* Otherwise call the wrapper. This should be equivalent for the rest of - compiler, so the code does not diverge, and the wrapper may run the - code necessary for keeping the profiling sane. */ - - switch (DECL_FUNCTION_CODE (fn)) - { - case BUILT_IN_FORK: - id = get_identifier ("__gcov_fork"); - break; - - case BUILT_IN_EXECL: - id = get_identifier ("__gcov_execl"); - break; - - case BUILT_IN_EXECV: - id = get_identifier ("__gcov_execv"); - break; - - case BUILT_IN_EXECLP: - id = get_identifier ("__gcov_execlp"); - break; - - case BUILT_IN_EXECLE: - id = get_identifier ("__gcov_execle"); - break; - - case BUILT_IN_EXECVP: - id = get_identifier ("__gcov_execvp"); - break; - - case BUILT_IN_EXECVE: - id = get_identifier ("__gcov_execve"); - break; - - default: - gcc_unreachable (); - } - - decl = build_decl (FUNCTION_DECL, id, TREE_TYPE (fn)); - DECL_EXTERNAL (decl) = 1; - TREE_PUBLIC (decl) = 1; - DECL_ARTIFICIAL (decl) = 1; - TREE_NOTHROW (decl) = 1; - DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; - DECL_VISIBILITY_SPECIFIED (decl) = 1; - call = build_function_call_expr (decl, arglist); - - return expand_call (call, target, ignore); -} - - -/* Reconstitute a mode for a __sync intrinsic operation. Since the type of - the pointer in these functions is void*, the tree optimizers may remove - casts. The mode computed in expand_builtin isn't reliable either, due - to __sync_bool_compare_and_swap. - - FCODE_DIFF should be fcode - base, where base is the FOO_1 code for the - group of builtins. This gives us log2 of the mode size. */ - -static inline enum machine_mode -get_builtin_sync_mode (int fcode_diff) -{ - /* The size is not negotiable, so ask not to get BLKmode in return - if the target indicates that a smaller size would be better. */ - return mode_for_size (BITS_PER_UNIT << fcode_diff, MODE_INT, 0); -} - -/* Expand the memory expression LOC and return the appropriate memory operand - for the builtin_sync operations. */ - -static rtx -get_builtin_sync_mem (tree loc, enum machine_mode mode) -{ - rtx addr, mem; - - addr = expand_expr (loc, NULL, Pmode, EXPAND_SUM); - - /* Note that we explicitly do not want any alias information for this - memory, so that we kill all other live memories. Otherwise we don't - satisfy the full barrier semantics of the intrinsic. */ - mem = validize_mem (gen_rtx_MEM (mode, addr)); - - set_mem_align (mem, get_pointer_alignment (loc, BIGGEST_ALIGNMENT)); - set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER); - MEM_VOLATILE_P (mem) = 1; - - return mem; -} - -/* Expand the __sync_xxx_and_fetch and __sync_fetch_and_xxx intrinsics. - ARGLIST is the operands list to the function. CODE is the rtx code - that corresponds to the arithmetic or logical operation from the name; - an exception here is that NOT actually means NAND. TARGET is an optional - place for us to store the results; AFTER is true if this is the - fetch_and_xxx form. IGNORE is true if we don't actually care about - the result of the operation at all. */ - -static rtx -expand_builtin_sync_operation (enum machine_mode mode, tree arglist, - enum rtx_code code, bool after, - rtx target, bool ignore) -{ - rtx val, mem; - enum machine_mode old_mode; - - /* Expand the operands. */ - mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode); - - arglist = TREE_CHAIN (arglist); - val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL); - /* If VAL is promoted to a wider mode, convert it back to MODE. Take care - of CONST_INTs, where we know the old_mode only from the call argument. */ - old_mode = GET_MODE (val); - if (old_mode == VOIDmode) - old_mode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))); - val = convert_modes (mode, old_mode, val, 1); - - if (ignore) - return expand_sync_operation (mem, val, code); - else - return expand_sync_fetch_operation (mem, val, code, after, target); -} - -/* Expand the __sync_val_compare_and_swap and __sync_bool_compare_and_swap - intrinsics. ARGLIST is the operands list to the function. IS_BOOL is - true if this is the boolean form. TARGET is a place for us to store the - results; this is NOT optional if IS_BOOL is true. */ - -static rtx -expand_builtin_compare_and_swap (enum machine_mode mode, tree arglist, - bool is_bool, rtx target) -{ - rtx old_val, new_val, mem; - enum machine_mode old_mode; - - /* Expand the operands. */ - mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode); - - arglist = TREE_CHAIN (arglist); - old_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL); - /* If VAL is promoted to a wider mode, convert it back to MODE. Take care - of CONST_INTs, where we know the old_mode only from the call argument. */ - old_mode = GET_MODE (old_val); - if (old_mode == VOIDmode) - old_mode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))); - old_val = convert_modes (mode, old_mode, old_val, 1); - - arglist = TREE_CHAIN (arglist); - new_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL); - /* If VAL is promoted to a wider mode, convert it back to MODE. Take care - of CONST_INTs, where we know the old_mode only from the call argument. */ - old_mode = GET_MODE (new_val); - if (old_mode == VOIDmode) - old_mode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))); - new_val = convert_modes (mode, old_mode, new_val, 1); - - if (is_bool) - return expand_bool_compare_and_swap (mem, old_val, new_val, target); - else - return expand_val_compare_and_swap (mem, old_val, new_val, target); -} - -/* Expand the __sync_lock_test_and_set intrinsic. Note that the most - general form is actually an atomic exchange, and some targets only - support a reduced form with the second argument being a constant 1. - ARGLIST is the operands list to the function; TARGET is an optional - place for us to store the results. */ - -static rtx -expand_builtin_lock_test_and_set (enum machine_mode mode, tree arglist, - rtx target) -{ - rtx val, mem; - enum machine_mode old_mode; - - /* Expand the operands. */ - mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode); - - arglist = TREE_CHAIN (arglist); - val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL); - /* If VAL is promoted to a wider mode, convert it back to MODE. Take care - of CONST_INTs, where we know the old_mode only from the call argument. */ - old_mode = GET_MODE (val); - if (old_mode == VOIDmode) - old_mode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))); - val = convert_modes (mode, old_mode, val, 1); - - return expand_sync_lock_test_and_set (mem, val, target); -} - -/* Expand the __sync_synchronize intrinsic. */ - -static void -expand_builtin_synchronize (void) -{ - tree x; - -#ifdef HAVE_memory_barrier - if (HAVE_memory_barrier) - { - emit_insn (gen_memory_barrier ()); - return; - } -#endif - - /* If no explicit memory barrier instruction is available, create an - empty asm stmt with a memory clobber. */ - x = build4 (ASM_EXPR, void_type_node, build_string (0, ""), NULL, NULL, - tree_cons (NULL, build_string (6, "memory"), NULL)); - ASM_VOLATILE_P (x) = 1; - expand_asm_expr (x); -} - -/* Expand the __sync_lock_release intrinsic. ARGLIST is the operands list - to the function. */ - -static void -expand_builtin_lock_release (enum machine_mode mode, tree arglist) -{ - enum insn_code icode; - rtx mem, insn; - rtx val = const0_rtx; - - /* Expand the operands. */ - mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode); - - /* If there is an explicit operation in the md file, use it. */ - icode = sync_lock_release[mode]; - if (icode != CODE_FOR_nothing) - { - if (!insn_data[icode].operand[1].predicate (val, mode)) - val = force_reg (mode, val); - - insn = GEN_FCN (icode) (mem, val); - if (insn) - { - emit_insn (insn); - return; - } - } - - /* Otherwise we can implement this operation by emitting a barrier - followed by a store of zero. */ - expand_builtin_synchronize (); - emit_move_insn (mem, val); -} /* Expand an expression EXP that calls a built-in function, with result going to TARGET if that's convenient @@ -5651,13 +4948,16 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp)); + /* Perform postincrements before expanding builtin functions. */ + emit_queue (); + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) - return targetm.expand_builtin (exp, target, subtarget, mode, ignore); + return (*targetm.expand_builtin) (exp, target, subtarget, mode, ignore); /* When not optimizing, generate calls to library functions for a certain set of builtins. */ if (!optimize - && !called_as_built_in (fndecl) + && !CALLED_AS_BUILT_IN (fndecl) && DECL_ASSEMBLER_NAME_SET_P (fndecl) && fcode != BUILT_IN_ALLOCA) return expand_call (exp, target, ignore); @@ -5694,101 +4994,106 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, switch (fcode) { - CASE_FLT_FN (BUILT_IN_FABS): - target = expand_builtin_fabs (arglist, target, subtarget); - if (target) - return target; - break; + case BUILT_IN_ABS: + case BUILT_IN_LABS: + case BUILT_IN_LLABS: + case BUILT_IN_IMAXABS: + /* build_function_call changes these into ABS_EXPR. */ + abort (); - CASE_FLT_FN (BUILT_IN_COPYSIGN): - target = expand_builtin_copysign (arglist, target, subtarget); + case BUILT_IN_FABS: + case BUILT_IN_FABSF: + case BUILT_IN_FABSL: + target = expand_builtin_fabs (arglist, target, subtarget); if (target) - return target; + return target; break; - /* Just do a normal library call if we were unable to fold - the values. */ - CASE_FLT_FN (BUILT_IN_CABS): + case BUILT_IN_CABS: + case BUILT_IN_CABSF: + case BUILT_IN_CABSL: + if (flag_unsafe_math_optimizations) + { + target = expand_builtin_cabs (arglist, target); + if (target) + return target; + } break; - CASE_FLT_FN (BUILT_IN_EXP): - CASE_FLT_FN (BUILT_IN_EXP10): - CASE_FLT_FN (BUILT_IN_POW10): - CASE_FLT_FN (BUILT_IN_EXP2): - CASE_FLT_FN (BUILT_IN_EXPM1): - CASE_FLT_FN (BUILT_IN_LOGB): - CASE_FLT_FN (BUILT_IN_ILOGB): - CASE_FLT_FN (BUILT_IN_LOG): - CASE_FLT_FN (BUILT_IN_LOG10): - CASE_FLT_FN (BUILT_IN_LOG2): - CASE_FLT_FN (BUILT_IN_LOG1P): - CASE_FLT_FN (BUILT_IN_TAN): - CASE_FLT_FN (BUILT_IN_ASIN): - CASE_FLT_FN (BUILT_IN_ACOS): - CASE_FLT_FN (BUILT_IN_ATAN): + case BUILT_IN_CONJ: + case BUILT_IN_CONJF: + case BUILT_IN_CONJL: + case BUILT_IN_CREAL: + case BUILT_IN_CREALF: + case BUILT_IN_CREALL: + case BUILT_IN_CIMAG: + case BUILT_IN_CIMAGF: + case BUILT_IN_CIMAGL: + /* expand_tree_builtin changes these into CONJ_EXPR, REALPART_EXPR + and IMAGPART_EXPR. */ + abort (); + + case BUILT_IN_SIN: + case BUILT_IN_SINF: + case BUILT_IN_SINL: + case BUILT_IN_COS: + case BUILT_IN_COSF: + case BUILT_IN_COSL: + case BUILT_IN_EXP: + case BUILT_IN_EXPF: + case BUILT_IN_EXPL: + case BUILT_IN_LOG: + case BUILT_IN_LOGF: + case BUILT_IN_LOGL: + case BUILT_IN_TAN: + case BUILT_IN_TANF: + case BUILT_IN_TANL: + case BUILT_IN_ATAN: + case BUILT_IN_ATANF: + case BUILT_IN_ATANL: /* Treat these like sqrt only if unsafe math optimizations are allowed, because of possible accuracy problems. */ if (! flag_unsafe_math_optimizations) break; - CASE_FLT_FN (BUILT_IN_SQRT): - CASE_FLT_FN (BUILT_IN_FLOOR): - CASE_FLT_FN (BUILT_IN_CEIL): - CASE_FLT_FN (BUILT_IN_TRUNC): - CASE_FLT_FN (BUILT_IN_ROUND): - CASE_FLT_FN (BUILT_IN_NEARBYINT): - CASE_FLT_FN (BUILT_IN_RINT): - CASE_FLT_FN (BUILT_IN_LRINT): - CASE_FLT_FN (BUILT_IN_LLRINT): + case BUILT_IN_SQRT: + case BUILT_IN_SQRTF: + case BUILT_IN_SQRTL: + case BUILT_IN_FLOOR: + case BUILT_IN_FLOORF: + case BUILT_IN_FLOORL: + case BUILT_IN_CEIL: + case BUILT_IN_CEILF: + case BUILT_IN_CEILL: + case BUILT_IN_TRUNC: + case BUILT_IN_TRUNCF: + case BUILT_IN_TRUNCL: + case BUILT_IN_ROUND: + case BUILT_IN_ROUNDF: + case BUILT_IN_ROUNDL: + case BUILT_IN_NEARBYINT: + case BUILT_IN_NEARBYINTF: + case BUILT_IN_NEARBYINTL: target = expand_builtin_mathfn (exp, target, subtarget); if (target) return target; break; - CASE_FLT_FN (BUILT_IN_LCEIL): - CASE_FLT_FN (BUILT_IN_LLCEIL): - CASE_FLT_FN (BUILT_IN_LFLOOR): - CASE_FLT_FN (BUILT_IN_LLFLOOR): - target = expand_builtin_int_roundingfn (exp, target, subtarget); - if (target) - return target; - break; - - CASE_FLT_FN (BUILT_IN_POW): - target = expand_builtin_pow (exp, target, subtarget); - if (target) - return target; - break; - - CASE_FLT_FN (BUILT_IN_POWI): - target = expand_builtin_powi (exp, target, subtarget); - if (target) - return target; - break; - - CASE_FLT_FN (BUILT_IN_ATAN2): - CASE_FLT_FN (BUILT_IN_LDEXP): - CASE_FLT_FN (BUILT_IN_FMOD): - CASE_FLT_FN (BUILT_IN_DREM): + case BUILT_IN_POW: + case BUILT_IN_POWF: + case BUILT_IN_POWL: if (! flag_unsafe_math_optimizations) break; - target = expand_builtin_mathfn_2 (exp, target, subtarget); - if (target) - return target; - break; - - CASE_FLT_FN (BUILT_IN_SIN): - CASE_FLT_FN (BUILT_IN_COS): - if (! flag_unsafe_math_optimizations) - break; - target = expand_builtin_mathfn_3 (exp, target, subtarget); + target = expand_builtin_pow (exp, target, subtarget); if (target) return target; break; - CASE_FLT_FN (BUILT_IN_SINCOS): + case BUILT_IN_ATAN2: + case BUILT_IN_ATAN2F: + case BUILT_IN_ATAN2L: if (! flag_unsafe_math_optimizations) break; - target = expand_builtin_sincos (exp); + target = expand_builtin_mathfn_2 (exp, target, subtarget); if (target) return target; break; @@ -5819,7 +5124,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, rtx ops[3]; for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++) - ops[i] = expand_normal (TREE_VALUE (t)); + ops[i] = expand_expr (TREE_VALUE (t), NULL_RTX, VOIDmode, 0); return expand_builtin_apply (ops[0], ops[1], ops[2]); } @@ -5829,7 +5134,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, memory returned by __builtin_apply. */ case BUILT_IN_RETURN: if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) - expand_builtin_return (expand_normal (TREE_VALUE (arglist))); + expand_builtin_return (expand_expr (TREE_VALUE (arglist), + NULL_RTX, VOIDmode, 0)); return const0_rtx; case BUILT_IN_SAVEREGS: @@ -5840,15 +5146,13 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, /* Return the address of the first anonymous stack arg. */ case BUILT_IN_NEXT_ARG: - if (fold_builtin_next_arg (arglist)) - return const0_rtx; - return expand_builtin_next_arg (); + return expand_builtin_next_arg (arglist); case BUILT_IN_CLASSIFY_TYPE: return expand_builtin_classify_type (arglist); case BUILT_IN_CONSTANT_P: - return const0_rtx; + return expand_builtin_constant_p (arglist, target_mode); case BUILT_IN_FRAME_ADDRESS: case BUILT_IN_RETURN_ADDRESS: @@ -5859,7 +5163,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, case BUILT_IN_AGGREGATE_INCOMING_ADDRESS: if (arglist != 0 || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))) - || !MEM_P (DECL_RTL (DECL_RESULT (current_function_decl)))) + || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM) return const0_rtx; else return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0); @@ -5870,47 +5174,45 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; - case BUILT_IN_STACK_SAVE: - return expand_stack_save (); - - case BUILT_IN_STACK_RESTORE: - expand_stack_restore (TREE_VALUE (arglist)); - return const0_rtx; - - CASE_INT_FN (BUILT_IN_FFS): - case BUILT_IN_FFSIMAX: + case BUILT_IN_FFS: + case BUILT_IN_FFSL: + case BUILT_IN_FFSLL: target = expand_builtin_unop (target_mode, arglist, target, subtarget, ffs_optab); if (target) return target; break; - CASE_INT_FN (BUILT_IN_CLZ): - case BUILT_IN_CLZIMAX: + case BUILT_IN_CLZ: + case BUILT_IN_CLZL: + case BUILT_IN_CLZLL: target = expand_builtin_unop (target_mode, arglist, target, subtarget, clz_optab); if (target) return target; break; - CASE_INT_FN (BUILT_IN_CTZ): - case BUILT_IN_CTZIMAX: + case BUILT_IN_CTZ: + case BUILT_IN_CTZL: + case BUILT_IN_CTZLL: target = expand_builtin_unop (target_mode, arglist, target, subtarget, ctz_optab); if (target) return target; break; - CASE_INT_FN (BUILT_IN_POPCOUNT): - case BUILT_IN_POPCOUNTIMAX: + case BUILT_IN_POPCOUNT: + case BUILT_IN_POPCOUNTL: + case BUILT_IN_POPCOUNTLL: target = expand_builtin_unop (target_mode, arglist, target, subtarget, popcount_optab); if (target) return target; break; - CASE_INT_FN (BUILT_IN_PARITY): - case BUILT_IN_PARITYIMAX: + case BUILT_IN_PARITY: + case BUILT_IN_PARITYL: + case BUILT_IN_PARITYLL: target = expand_builtin_unop (target_mode, arglist, target, subtarget, parity_optab); if (target) @@ -5924,25 +5226,25 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, break; case BUILT_IN_STRCPY: - target = expand_builtin_strcpy (fndecl, arglist, target, mode); + target = expand_builtin_strcpy (arglist, target, mode); if (target) return target; break; case BUILT_IN_STRNCPY: - target = expand_builtin_strncpy (exp, target, mode); + target = expand_builtin_strncpy (arglist, target, mode); if (target) return target; break; case BUILT_IN_STPCPY: - target = expand_builtin_stpcpy (exp, target, mode); + target = expand_builtin_stpcpy (arglist, target, mode); if (target) return target; break; case BUILT_IN_STRCAT: - target = expand_builtin_strcat (fndecl, arglist, target, mode); + target = expand_builtin_strcat (arglist, target, mode); if (target) return target; break; @@ -5966,64 +5268,63 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, break; case BUILT_IN_STRSTR: - target = expand_builtin_strstr (arglist, TREE_TYPE (exp), target, mode); + target = expand_builtin_strstr (arglist, target, mode); if (target) return target; break; case BUILT_IN_STRPBRK: - target = expand_builtin_strpbrk (arglist, TREE_TYPE (exp), target, mode); + target = expand_builtin_strpbrk (arglist, target, mode); if (target) return target; break; case BUILT_IN_INDEX: case BUILT_IN_STRCHR: - target = expand_builtin_strchr (arglist, TREE_TYPE (exp), target, mode); + target = expand_builtin_strchr (arglist, target, mode); if (target) return target; break; case BUILT_IN_RINDEX: case BUILT_IN_STRRCHR: - target = expand_builtin_strrchr (arglist, TREE_TYPE (exp), target, mode); + target = expand_builtin_strrchr (arglist, target, mode); if (target) return target; break; case BUILT_IN_MEMCPY: - target = expand_builtin_memcpy (exp, target, mode); + target = expand_builtin_memcpy (arglist, target, mode); if (target) return target; break; case BUILT_IN_MEMPCPY: - target = expand_builtin_mempcpy (arglist, TREE_TYPE (exp), target, mode, /*endp=*/ 1); + target = expand_builtin_mempcpy (arglist, target, mode, /*endp=*/ 1); if (target) return target; break; case BUILT_IN_MEMMOVE: - target = expand_builtin_memmove (arglist, TREE_TYPE (exp), target, - mode, exp); + target = expand_builtin_memmove (arglist, target, mode); if (target) return target; break; case BUILT_IN_BCOPY: - target = expand_builtin_bcopy (exp); + target = expand_builtin_bcopy (arglist); if (target) return target; break; case BUILT_IN_MEMSET: - target = expand_builtin_memset (arglist, target, mode, exp); + target = expand_builtin_memset (arglist, target, mode); if (target) return target; break; case BUILT_IN_BZERO: - target = expand_builtin_bzero (exp); + target = expand_builtin_bzero (arglist); if (target) return target; break; @@ -6048,110 +5349,46 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, break; case BUILT_IN_SETJMP: - /* This should have been lowered to the builtins below. */ - gcc_unreachable (); - - case BUILT_IN_SETJMP_SETUP: - /* __builtin_setjmp_setup is passed a pointer to an array of five words - and the receiver label. */ - if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - { - rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget, - VOIDmode, EXPAND_NORMAL); - tree label = TREE_OPERAND (TREE_VALUE (TREE_CHAIN (arglist)), 0); - rtx label_r = label_rtx (label); - - /* This is copied from the handling of non-local gotos. */ - expand_builtin_setjmp_setup (buf_addr, label_r); - nonlocal_goto_handler_labels - = gen_rtx_EXPR_LIST (VOIDmode, label_r, - nonlocal_goto_handler_labels); - /* ??? Do not let expand_label treat us as such since we would - not want to be both on the list of non-local labels and on - the list of forced labels. */ - FORCED_LABEL (label) = 0; - return const0_rtx; - } - break; - - case BUILT_IN_SETJMP_DISPATCHER: - /* __builtin_setjmp_dispatcher is passed the dispatcher label. */ - if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) - { - tree label = TREE_OPERAND (TREE_VALUE (arglist), 0); - rtx label_r = label_rtx (label); - - /* Remove the dispatcher label from the list of non-local labels - since the receiver labels have been added to it above. */ - remove_node_from_expr_list (label_r, &nonlocal_goto_handler_labels); - return const0_rtx; - } - break; - - case BUILT_IN_SETJMP_RECEIVER: - /* __builtin_setjmp_receiver is passed the receiver label. */ - if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) - { - tree label = TREE_OPERAND (TREE_VALUE (arglist), 0); - rtx label_r = label_rtx (label); - - expand_builtin_setjmp_receiver (label_r); - return const0_rtx; - } + target = expand_builtin_setjmp (arglist, target); + if (target) + return target; break; /* __builtin_longjmp is passed a pointer to an array of five words. It's similar to the C library longjmp function but works with __builtin_setjmp above. */ case BUILT_IN_LONGJMP: - if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + break; + else { rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget, - VOIDmode, EXPAND_NORMAL); - rtx value = expand_normal (TREE_VALUE (TREE_CHAIN (arglist))); + VOIDmode, 0); + rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), + NULL_RTX, VOIDmode, 0); if (value != const1_rtx) { - error ("%<__builtin_longjmp%> second argument must be 1"); + error ("__builtin_longjmp second argument must be 1"); return const0_rtx; } expand_builtin_longjmp (buf_addr, value); return const0_rtx; } - break; - - case BUILT_IN_NONLOCAL_GOTO: - target = expand_builtin_nonlocal_goto (arglist); - if (target) - return target; - break; - - /* This updates the setjmp buffer that is its argument with the value - of the current stack pointer. */ - case BUILT_IN_UPDATE_SETJMP_BUF: - if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) - { - rtx buf_addr - = expand_normal (TREE_VALUE (arglist)); - - expand_builtin_update_setjmp_buf (buf_addr); - return const0_rtx; - } - break; case BUILT_IN_TRAP: expand_builtin_trap (); return const0_rtx; case BUILT_IN_PRINTF: - target = expand_builtin_printf (exp, target, mode, false); + target = expand_builtin_printf (arglist, target, mode, false); if (target) return target; break; case BUILT_IN_PRINTF_UNLOCKED: - target = expand_builtin_printf (exp, target, mode, true); + target = expand_builtin_printf (arglist, target, mode, true); if (target) return target; break; @@ -6161,6 +5398,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, if (target) return target; break; + case BUILT_IN_FPUTS_UNLOCKED: target = expand_builtin_fputs (arglist, target, true); if (target) @@ -6168,13 +5406,13 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, break; case BUILT_IN_FPRINTF: - target = expand_builtin_fprintf (exp, target, mode, false); + target = expand_builtin_fprintf (arglist, target, mode, false); if (target) return target; break; case BUILT_IN_FPRINTF_UNLOCKED: - target = expand_builtin_fprintf (exp, target, mode, true); + target = expand_builtin_fprintf (arglist, target, mode, true); if (target) return target; break; @@ -6185,12 +5423,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; - CASE_FLT_FN (BUILT_IN_SIGNBIT): - target = expand_builtin_signbit (exp, target); - if (target) - return target; - break; - /* Various hooks for the DWARF 2 __throw routine. */ case BUILT_IN_UNWIND_INIT: expand_builtin_unwind_init (); @@ -6232,251 +5464,11 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, expand_builtin_prefetch (arglist); return const0_rtx; - case BUILT_IN_PROFILE_FUNC_ENTER: - return expand_builtin_profile_func (false); - case BUILT_IN_PROFILE_FUNC_EXIT: - return expand_builtin_profile_func (true); - - case BUILT_IN_INIT_TRAMPOLINE: - return expand_builtin_init_trampoline (arglist); - case BUILT_IN_ADJUST_TRAMPOLINE: - return expand_builtin_adjust_trampoline (arglist); - - case BUILT_IN_FORK: - case BUILT_IN_EXECL: - case BUILT_IN_EXECV: - case BUILT_IN_EXECLP: - case BUILT_IN_EXECLE: - case BUILT_IN_EXECVP: - case BUILT_IN_EXECVE: - target = expand_builtin_fork_or_exec (fndecl, arglist, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_FETCH_AND_ADD_1: - case BUILT_IN_FETCH_AND_ADD_2: - case BUILT_IN_FETCH_AND_ADD_4: - case BUILT_IN_FETCH_AND_ADD_8: - case BUILT_IN_FETCH_AND_ADD_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_ADD_1); - target = expand_builtin_sync_operation (mode, arglist, PLUS, - false, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_FETCH_AND_SUB_1: - case BUILT_IN_FETCH_AND_SUB_2: - case BUILT_IN_FETCH_AND_SUB_4: - case BUILT_IN_FETCH_AND_SUB_8: - case BUILT_IN_FETCH_AND_SUB_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_SUB_1); - target = expand_builtin_sync_operation (mode, arglist, MINUS, - false, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_FETCH_AND_OR_1: - case BUILT_IN_FETCH_AND_OR_2: - case BUILT_IN_FETCH_AND_OR_4: - case BUILT_IN_FETCH_AND_OR_8: - case BUILT_IN_FETCH_AND_OR_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_OR_1); - target = expand_builtin_sync_operation (mode, arglist, IOR, - false, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_FETCH_AND_AND_1: - case BUILT_IN_FETCH_AND_AND_2: - case BUILT_IN_FETCH_AND_AND_4: - case BUILT_IN_FETCH_AND_AND_8: - case BUILT_IN_FETCH_AND_AND_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_AND_1); - target = expand_builtin_sync_operation (mode, arglist, AND, - false, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_FETCH_AND_XOR_1: - case BUILT_IN_FETCH_AND_XOR_2: - case BUILT_IN_FETCH_AND_XOR_4: - case BUILT_IN_FETCH_AND_XOR_8: - case BUILT_IN_FETCH_AND_XOR_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_XOR_1); - target = expand_builtin_sync_operation (mode, arglist, XOR, - false, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_FETCH_AND_NAND_1: - case BUILT_IN_FETCH_AND_NAND_2: - case BUILT_IN_FETCH_AND_NAND_4: - case BUILT_IN_FETCH_AND_NAND_8: - case BUILT_IN_FETCH_AND_NAND_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_NAND_1); - target = expand_builtin_sync_operation (mode, arglist, NOT, - false, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_ADD_AND_FETCH_1: - case BUILT_IN_ADD_AND_FETCH_2: - case BUILT_IN_ADD_AND_FETCH_4: - case BUILT_IN_ADD_AND_FETCH_8: - case BUILT_IN_ADD_AND_FETCH_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_ADD_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, arglist, PLUS, - true, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_SUB_AND_FETCH_1: - case BUILT_IN_SUB_AND_FETCH_2: - case BUILT_IN_SUB_AND_FETCH_4: - case BUILT_IN_SUB_AND_FETCH_8: - case BUILT_IN_SUB_AND_FETCH_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_SUB_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, arglist, MINUS, - true, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_OR_AND_FETCH_1: - case BUILT_IN_OR_AND_FETCH_2: - case BUILT_IN_OR_AND_FETCH_4: - case BUILT_IN_OR_AND_FETCH_8: - case BUILT_IN_OR_AND_FETCH_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_OR_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, arglist, IOR, - true, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_AND_AND_FETCH_1: - case BUILT_IN_AND_AND_FETCH_2: - case BUILT_IN_AND_AND_FETCH_4: - case BUILT_IN_AND_AND_FETCH_8: - case BUILT_IN_AND_AND_FETCH_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_AND_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, arglist, AND, - true, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_XOR_AND_FETCH_1: - case BUILT_IN_XOR_AND_FETCH_2: - case BUILT_IN_XOR_AND_FETCH_4: - case BUILT_IN_XOR_AND_FETCH_8: - case BUILT_IN_XOR_AND_FETCH_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_XOR_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, arglist, XOR, - true, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_NAND_AND_FETCH_1: - case BUILT_IN_NAND_AND_FETCH_2: - case BUILT_IN_NAND_AND_FETCH_4: - case BUILT_IN_NAND_AND_FETCH_8: - case BUILT_IN_NAND_AND_FETCH_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_NAND_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, arglist, NOT, - true, target, ignore); - if (target) - return target; - break; - - case BUILT_IN_BOOL_COMPARE_AND_SWAP_1: - case BUILT_IN_BOOL_COMPARE_AND_SWAP_2: - case BUILT_IN_BOOL_COMPARE_AND_SWAP_4: - case BUILT_IN_BOOL_COMPARE_AND_SWAP_8: - case BUILT_IN_BOOL_COMPARE_AND_SWAP_16: - if (mode == VOIDmode) - mode = TYPE_MODE (boolean_type_node); - if (!target || !register_operand (target, mode)) - target = gen_reg_rtx (mode); - - mode = get_builtin_sync_mode (fcode - BUILT_IN_BOOL_COMPARE_AND_SWAP_1); - target = expand_builtin_compare_and_swap (mode, arglist, true, target); - if (target) - return target; - break; - - case BUILT_IN_VAL_COMPARE_AND_SWAP_1: - case BUILT_IN_VAL_COMPARE_AND_SWAP_2: - case BUILT_IN_VAL_COMPARE_AND_SWAP_4: - case BUILT_IN_VAL_COMPARE_AND_SWAP_8: - case BUILT_IN_VAL_COMPARE_AND_SWAP_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_VAL_COMPARE_AND_SWAP_1); - target = expand_builtin_compare_and_swap (mode, arglist, false, target); - if (target) - return target; - break; - - case BUILT_IN_LOCK_TEST_AND_SET_1: - case BUILT_IN_LOCK_TEST_AND_SET_2: - case BUILT_IN_LOCK_TEST_AND_SET_4: - case BUILT_IN_LOCK_TEST_AND_SET_8: - case BUILT_IN_LOCK_TEST_AND_SET_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_TEST_AND_SET_1); - target = expand_builtin_lock_test_and_set (mode, arglist, target); - if (target) - return target; - break; - - case BUILT_IN_LOCK_RELEASE_1: - case BUILT_IN_LOCK_RELEASE_2: - case BUILT_IN_LOCK_RELEASE_4: - case BUILT_IN_LOCK_RELEASE_8: - case BUILT_IN_LOCK_RELEASE_16: - mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_RELEASE_1); - expand_builtin_lock_release (mode, arglist); - return const0_rtx; - - case BUILT_IN_SYNCHRONIZE: - expand_builtin_synchronize (); - return const0_rtx; - - case BUILT_IN_OBJECT_SIZE: - return expand_builtin_object_size (exp); - - case BUILT_IN_MEMCPY_CHK: - case BUILT_IN_MEMPCPY_CHK: - case BUILT_IN_MEMMOVE_CHK: - case BUILT_IN_MEMSET_CHK: - target = expand_builtin_memory_chk (exp, target, mode, fcode); - if (target) - return target; - break; - - case BUILT_IN_STRCPY_CHK: - case BUILT_IN_STPCPY_CHK: - case BUILT_IN_STRNCPY_CHK: - case BUILT_IN_STRCAT_CHK: - case BUILT_IN_SNPRINTF_CHK: - case BUILT_IN_VSNPRINTF_CHK: - maybe_emit_chk_warning (exp, fcode); - break; - - case BUILT_IN_SPRINTF_CHK: - case BUILT_IN_VSPRINTF_CHK: - maybe_emit_sprintf_chk_warning (exp, fcode); - break; default: /* just do library call, if unknown builtin */ - break; + if (!DECL_ASSEMBLER_NAME_SET_P (fndecl)) + error ("built-in function `%s' not currently supported", + IDENTIFIER_POINTER (DECL_NAME (fndecl))); } /* The switch statement above can drop through to cause the function @@ -6573,19 +5565,12 @@ fold_builtin_constant_p (tree arglist) STRIP_NOPS (arglist); /* If we know this is a constant, emit the constant of one. */ - if (CONSTANT_CLASS_P (arglist) + if (TREE_CODE_CLASS (TREE_CODE (arglist)) == 'c' || (TREE_CODE (arglist) == CONSTRUCTOR - && TREE_CONSTANT (arglist))) + && TREE_CONSTANT (arglist)) + || (TREE_CODE (arglist) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arglist, 0)) == STRING_CST)) return integer_one_node; - if (TREE_CODE (arglist) == ADDR_EXPR) - { - tree op = TREE_OPERAND (arglist, 0); - if (TREE_CODE (op) == STRING_CST - || (TREE_CODE (op) == ARRAY_REF - && integer_zerop (TREE_OPERAND (op, 1)) - && TREE_CODE (TREE_OPERAND (op, 0)) == STRING_CST)) - return integer_one_node; - } /* If this expression has side effects, show we don't know it to be a constant. Likewise if it's a pointer or aggregate type since in @@ -6597,84 +5582,21 @@ fold_builtin_constant_p (tree arglist) if (TREE_SIDE_EFFECTS (arglist) || AGGREGATE_TYPE_P (TREE_TYPE (arglist)) || POINTER_TYPE_P (TREE_TYPE (arglist)) - || cfun == 0 - || folding_initializer) + || cfun == 0) return integer_zero_node; return 0; } -/* Fold a call to __builtin_expect, if we expect that a comparison against - the argument will fold to a constant. In practice, this means a true - constant or the address of a non-weak symbol. ARGLIST is the argument - list of the call. */ - -static tree -fold_builtin_expect (tree arglist) -{ - tree arg, inner; - - if (arglist == 0) - return 0; - - arg = TREE_VALUE (arglist); - - /* If the argument isn't invariant, then there's nothing we can do. */ - if (!TREE_INVARIANT (arg)) - return 0; - - /* If we're looking at an address of a weak decl, then do not fold. */ - inner = arg; - STRIP_NOPS (inner); - if (TREE_CODE (inner) == ADDR_EXPR) - { - do - { - inner = TREE_OPERAND (inner, 0); - } - while (TREE_CODE (inner) == COMPONENT_REF - || TREE_CODE (inner) == ARRAY_REF); - if (DECL_P (inner) && DECL_WEAK (inner)) - return 0; - } - - /* Otherwise, ARG already has the proper type for the return value. */ - return arg; -} - /* Fold a call to __builtin_classify_type. */ static tree fold_builtin_classify_type (tree arglist) { if (arglist == 0) - return build_int_cst (NULL_TREE, no_type_class); + return build_int_2 (no_type_class, 0); - return build_int_cst (NULL_TREE, - type_to_class (TREE_TYPE (TREE_VALUE (arglist)))); -} - -/* Fold a call to __builtin_strlen. */ - -static tree -fold_builtin_strlen (tree arglist) -{ - if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) - return NULL_TREE; - else - { - tree len = c_strlen (TREE_VALUE (arglist), 0); - - if (len) - { - /* Convert from the internal "sizetype" type to "size_t". */ - if (size_type_node) - len = fold_convert (size_type_node, len); - return len; - } - - return NULL_TREE; - } + return build_int_2 (type_to_class (TREE_TYPE (TREE_VALUE (arglist))), 0); } /* Fold a call to __builtin_inf or __builtin_huge_val. */ @@ -6684,15 +5606,8 @@ fold_builtin_inf (tree type, int warn) { REAL_VALUE_TYPE real; - /* __builtin_inff is intended to be usable to define INFINITY on all - targets. If an infinity is not available, INFINITY expands "to a - positive constant of type float that overflows at translation - time", footnote "In this case, using INFINITY will violate the - constraint in 6.4.4 and thus require a diagnostic." (C99 7.12#4). - Thus we pedwarn to ensure this constraint violation is - diagnosed. */ if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn) - pedwarn ("target format does not support infinity"); + warning ("target format does not support infinity"); real_inf (&real); return build_real (type, real); @@ -6754,13 +5669,12 @@ integer_valued_real_p (tree t) case REAL_CST: if (! TREE_CONSTANT_OVERFLOW (t)) { - REAL_VALUE_TYPE c, cint; + REAL_VALUE_TYPE c, cint; c = TREE_REAL_CST (t); real_trunc (&cint, TYPE_MODE (TREE_TYPE (t)), &c); return real_identical (&c, &cint); } - break; case NOP_EXPR: { @@ -6775,12 +5689,21 @@ integer_valued_real_p (tree t) case CALL_EXPR: switch (builtin_mathfn_code (t)) { - CASE_FLT_FN (BUILT_IN_CEIL): - CASE_FLT_FN (BUILT_IN_FLOOR): - CASE_FLT_FN (BUILT_IN_NEARBYINT): - CASE_FLT_FN (BUILT_IN_RINT): - CASE_FLT_FN (BUILT_IN_ROUND): - CASE_FLT_FN (BUILT_IN_TRUNC): + case BUILT_IN_CEIL: + case BUILT_IN_CEILF: + case BUILT_IN_CEILL: + case BUILT_IN_FLOOR: + case BUILT_IN_FLOORF: + case BUILT_IN_FLOORL: + case BUILT_IN_NEARBYINT: + case BUILT_IN_NEARBYINTF: + case BUILT_IN_NEARBYINTL: + case BUILT_IN_ROUND: + case BUILT_IN_ROUNDF: + case BUILT_IN_ROUNDL: + case BUILT_IN_TRUNC: + case BUILT_IN_TRUNCF: + case BUILT_IN_TRUNCL: return true; default: @@ -6799,8 +5722,10 @@ integer_valued_real_p (tree t) Do the transformation. */ static tree -fold_trunc_transparent_mathfn (tree fndecl, tree arglist) +fold_trunc_transparent_mathfn (tree exp) { + tree fndecl = get_callee_fndecl (exp); + tree arglist = TREE_OPERAND (exp, 1); enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); tree arg; @@ -6820,45 +5745,7 @@ fold_trunc_transparent_mathfn (tree fndecl, tree arglist) if (optimize) { tree arg0 = strip_float_extensions (arg); - tree ftype = TREE_TYPE (TREE_TYPE (fndecl)); - tree newtype = TREE_TYPE (arg0); - tree decl; - - if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype) - && (decl = mathfn_built_in (newtype, fcode))) - { - arglist = - build_tree_list (NULL_TREE, fold_convert (newtype, arg0)); - return fold_convert (ftype, - build_function_call_expr (decl, arglist)); - } - } - return 0; -} - -/* EXP is assumed to be builtin call which can narrow the FP type of - the argument, for instance lround((double)f) -> lroundf (f). */ - -static tree -fold_fixed_mathfn (tree fndecl, tree arglist) -{ - enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); - tree arg; - - if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return 0; - - arg = TREE_VALUE (arglist); - - /* If argument is already integer valued, and we don't need to worry - about setting errno, there's no need to perform rounding. */ - if (! flag_errno_math && integer_valued_real_p (arg)) - return fold_build1 (FIX_TRUNC_EXPR, TREE_TYPE (TREE_TYPE (fndecl)), arg); - - if (optimize) - { - tree ftype = TREE_TYPE (arg); - tree arg0 = strip_float_extensions (arg); + tree ftype = TREE_TYPE (exp); tree newtype = TREE_TYPE (arg0); tree decl; @@ -6866,56 +5753,20 @@ fold_fixed_mathfn (tree fndecl, tree arglist) && (decl = mathfn_built_in (newtype, fcode))) { arglist = - build_tree_list (NULL_TREE, fold_convert (newtype, arg0)); - return build_function_call_expr (decl, arglist); - } - } - - /* Canonicalize llround (x) to lround (x) on LP64 targets where - sizeof (long long) == sizeof (long). */ - if (TYPE_PRECISION (long_long_integer_type_node) - == TYPE_PRECISION (long_integer_type_node)) - { - tree newfn = NULL_TREE; - switch (fcode) - { - CASE_FLT_FN (BUILT_IN_LLCEIL): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LCEIL); - break; - - CASE_FLT_FN (BUILT_IN_LLFLOOR): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LFLOOR); - break; - - CASE_FLT_FN (BUILT_IN_LLROUND): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LROUND); - break; - - CASE_FLT_FN (BUILT_IN_LLRINT): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LRINT); - break; - - default: - break; - } - - if (newfn) - { - tree newcall = build_function_call_expr (newfn, arglist); - return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), newcall); + build_tree_list (NULL_TREE, fold (convert (newtype, arg0))); + return convert (ftype, + build_function_call_expr (decl, arglist)); } } - return 0; } -/* Fold function call to builtin cabs, cabsf or cabsl. ARGLIST - is the argument list, TYPE is the return type and FNDECL is the - original function DECL. Return NULL_TREE if no if no simplification - can be made. */ +/* Fold function call to builtin cabs, cabsf or cabsl. FNDECL is the + function's DECL, ARGLIST is the argument list and TYPE is the return + type. Return NULL_TREE if no simplification can be made. */ static tree -fold_builtin_cabs (tree arglist, tree type, tree fndecl) +fold_builtin_cabs (tree fndecl, tree arglist, tree type) { tree arg; @@ -6951,42 +5802,43 @@ fold_builtin_cabs (tree arglist, tree type, tree fndecl) /* If either part is zero, cabs is fabs of the other. */ if (TREE_CODE (arg) == COMPLEX_EXPR && real_zerop (TREE_OPERAND (arg, 0))) - return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg, 1)); + return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 1))); if (TREE_CODE (arg) == COMPLEX_EXPR && real_zerop (TREE_OPERAND (arg, 1))) - return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0)); + return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0))); - /* Optimize cabs(-z) and cabs(conj(z)) as cabs(z). */ - if (TREE_CODE (arg) == NEGATE_EXPR - || TREE_CODE (arg) == CONJ_EXPR) + if (flag_unsafe_math_optimizations) { - tree arglist = build_tree_list (NULL_TREE, TREE_OPERAND (arg, 0)); - return build_function_call_expr (fndecl, arglist); - } + enum built_in_function fcode; + tree sqrtfn; - /* Don't do this when optimizing for size. */ - if (flag_unsafe_math_optimizations - && optimize && !optimize_size) - { - tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT); + fcode = DECL_FUNCTION_CODE (fndecl); + if (fcode == BUILT_IN_CABS) + sqrtfn = implicit_built_in_decls[BUILT_IN_SQRT]; + else if (fcode == BUILT_IN_CABSF) + sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTF]; + else if (fcode == BUILT_IN_CABSL) + sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTL]; + else + sqrtfn = NULL_TREE; if (sqrtfn != NULL_TREE) { tree rpart, ipart, result, arglist; - arg = builtin_save_expr (arg); + arg = save_expr (arg); - rpart = fold_build1 (REALPART_EXPR, type, arg); - ipart = fold_build1 (IMAGPART_EXPR, type, arg); + rpart = fold (build1 (REALPART_EXPR, type, arg)); + ipart = fold (build1 (IMAGPART_EXPR, type, arg)); - rpart = builtin_save_expr (rpart); - ipart = builtin_save_expr (ipart); + rpart = save_expr (rpart); + ipart = save_expr (ipart); - result = fold_build2 (PLUS_EXPR, type, - fold_build2 (MULT_EXPR, type, - rpart, rpart), - fold_build2 (MULT_EXPR, type, - ipart, ipart)); + result = fold (build (PLUS_EXPR, type, + fold (build (MULT_EXPR, type, + rpart, rpart)), + fold (build (MULT_EXPR, type, + ipart, ipart)))); arglist = build_tree_list (NULL_TREE, result); return build_function_call_expr (sqrtfn, arglist); @@ -6996,286 +5848,13 @@ fold_builtin_cabs (tree arglist, tree type, tree fndecl) return NULL_TREE; } -/* Fold a builtin function call to sqrt, sqrtf, or sqrtl. Return - NULL_TREE if no simplification can be made. */ - -static tree -fold_builtin_sqrt (tree arglist, tree type) -{ - - enum built_in_function fcode; - tree arg = TREE_VALUE (arglist); - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - /* Optimize sqrt of constant value. */ - if (TREE_CODE (arg) == REAL_CST - && ! TREE_CONSTANT_OVERFLOW (arg)) - { - REAL_VALUE_TYPE r, x; - - x = TREE_REAL_CST (arg); - if (real_sqrt (&r, TYPE_MODE (type), &x) - || (!flag_trapping_math && !flag_errno_math)) - return build_real (type, r); - } - - /* Optimize sqrt(expN(x)) = expN(x*0.5). */ - fcode = builtin_mathfn_code (arg); - if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode)) - { - tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0); - arg = fold_build2 (MULT_EXPR, type, - TREE_VALUE (TREE_OPERAND (arg, 1)), - build_real (type, dconsthalf)); - arglist = build_tree_list (NULL_TREE, arg); - return build_function_call_expr (expfn, arglist); - } - - /* Optimize sqrt(Nroot(x)) -> pow(x,1/(2*N)). */ - if (flag_unsafe_math_optimizations && BUILTIN_ROOT_P (fcode)) - { - tree powfn = mathfn_built_in (type, BUILT_IN_POW); - - if (powfn) - { - tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1)); - tree tree_root; - /* The inner root was either sqrt or cbrt. */ - REAL_VALUE_TYPE dconstroot = - BUILTIN_SQRT_P (fcode) ? dconsthalf : dconstthird; - - /* Adjust for the outer root. */ - SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1); - dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); - tree_root = build_real (type, dconstroot); - arglist = tree_cons (NULL_TREE, arg0, - build_tree_list (NULL_TREE, tree_root)); - return build_function_call_expr (powfn, arglist); - } - } - - /* Optimize sqrt(pow(x,y)) = pow(|x|,y*0.5). */ - if (flag_unsafe_math_optimizations - && (fcode == BUILT_IN_POW - || fcode == BUILT_IN_POWF - || fcode == BUILT_IN_POWL)) - { - tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0); - tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1)); - tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1))); - tree narg1; - if (!tree_expr_nonnegative_p (arg0)) - arg0 = build1 (ABS_EXPR, type, arg0); - narg1 = fold_build2 (MULT_EXPR, type, arg1, - build_real (type, dconsthalf)); - arglist = tree_cons (NULL_TREE, arg0, - build_tree_list (NULL_TREE, narg1)); - return build_function_call_expr (powfn, arglist); - } - - return NULL_TREE; -} - -/* Fold a builtin function call to cbrt, cbrtf, or cbrtl. Return - NULL_TREE if no simplification can be made. */ -static tree -fold_builtin_cbrt (tree arglist, tree type) -{ - tree arg = TREE_VALUE (arglist); - const enum built_in_function fcode = builtin_mathfn_code (arg); - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - /* Optimize cbrt of constant value. */ - if (real_zerop (arg) || real_onep (arg) || real_minus_onep (arg)) - return arg; - - if (flag_unsafe_math_optimizations) - { - /* Optimize cbrt(expN(x)) -> expN(x/3). */ - if (BUILTIN_EXPONENT_P (fcode)) - { - tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0); - const REAL_VALUE_TYPE third_trunc = - real_value_truncate (TYPE_MODE (type), dconstthird); - arg = fold_build2 (MULT_EXPR, type, - TREE_VALUE (TREE_OPERAND (arg, 1)), - build_real (type, third_trunc)); - arglist = build_tree_list (NULL_TREE, arg); - return build_function_call_expr (expfn, arglist); - } - - /* Optimize cbrt(sqrt(x)) -> pow(x,1/6). */ - if (BUILTIN_SQRT_P (fcode)) - { - tree powfn = mathfn_built_in (type, BUILT_IN_POW); - - if (powfn) - { - tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1)); - tree tree_root; - REAL_VALUE_TYPE dconstroot = dconstthird; - - SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1); - dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); - tree_root = build_real (type, dconstroot); - arglist = tree_cons (NULL_TREE, arg0, - build_tree_list (NULL_TREE, tree_root)); - return build_function_call_expr (powfn, arglist); - } - } - - /* Optimize cbrt(cbrt(x)) -> pow(x,1/9) iff x is nonnegative. */ - if (BUILTIN_CBRT_P (fcode)) - { - tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1)); - if (tree_expr_nonnegative_p (arg0)) - { - tree powfn = mathfn_built_in (type, BUILT_IN_POW); - - if (powfn) - { - tree tree_root; - REAL_VALUE_TYPE dconstroot; - - real_arithmetic (&dconstroot, MULT_EXPR, &dconstthird, &dconstthird); - dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); - tree_root = build_real (type, dconstroot); - arglist = tree_cons (NULL_TREE, arg0, - build_tree_list (NULL_TREE, tree_root)); - return build_function_call_expr (powfn, arglist); - } - } - } - - /* Optimize cbrt(pow(x,y)) -> pow(x,y/3) iff x is nonnegative. */ - if (fcode == BUILT_IN_POW || fcode == BUILT_IN_POWF - || fcode == BUILT_IN_POWL) - { - tree arg00 = TREE_VALUE (TREE_OPERAND (arg, 1)); - tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1))); - if (tree_expr_nonnegative_p (arg00)) - { - tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0); - const REAL_VALUE_TYPE dconstroot - = real_value_truncate (TYPE_MODE (type), dconstthird); - tree narg01 = fold_build2 (MULT_EXPR, type, arg01, - build_real (type, dconstroot)); - arglist = tree_cons (NULL_TREE, arg00, - build_tree_list (NULL_TREE, narg01)); - return build_function_call_expr (powfn, arglist); - } - } - } - return NULL_TREE; -} - -/* Fold function call to builtin sin, sinf, or sinl. Return - NULL_TREE if no simplification can be made. */ -static tree -fold_builtin_sin (tree arglist) -{ - tree arg = TREE_VALUE (arglist); - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - /* Optimize sin (0.0) = 0.0. */ - if (real_zerop (arg)) - return arg; - - return NULL_TREE; -} - -/* Fold function call to builtin cos, cosf, or cosl. Return - NULL_TREE if no simplification can be made. */ -static tree -fold_builtin_cos (tree arglist, tree type, tree fndecl) -{ - tree arg = TREE_VALUE (arglist); - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - /* Optimize cos (0.0) = 1.0. */ - if (real_zerop (arg)) - return build_real (type, dconst1); - - /* Optimize cos(-x) into cos (x). */ - if (TREE_CODE (arg) == NEGATE_EXPR) - { - tree args = build_tree_list (NULL_TREE, - TREE_OPERAND (arg, 0)); - return build_function_call_expr (fndecl, args); - } - - return NULL_TREE; -} - -/* Fold function call to builtin tan, tanf, or tanl. Return - NULL_TREE if no simplification can be made. */ -static tree -fold_builtin_tan (tree arglist) -{ - enum built_in_function fcode; - tree arg = TREE_VALUE (arglist); - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - /* Optimize tan(0.0) = 0.0. */ - if (real_zerop (arg)) - return arg; - - /* Optimize tan(atan(x)) = x. */ - fcode = builtin_mathfn_code (arg); - if (flag_unsafe_math_optimizations - && (fcode == BUILT_IN_ATAN - || fcode == BUILT_IN_ATANF - || fcode == BUILT_IN_ATANL)) - return TREE_VALUE (TREE_OPERAND (arg, 1)); - - return NULL_TREE; -} - -/* Fold function call to builtin atan, atanf, or atanl. Return - NULL_TREE if no simplification can be made. */ - -static tree -fold_builtin_atan (tree arglist, tree type) -{ - - tree arg = TREE_VALUE (arglist); - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - /* Optimize atan(0.0) = 0.0. */ - if (real_zerop (arg)) - return arg; - - /* Optimize atan(1.0) = pi/4. */ - if (real_onep (arg)) - { - REAL_VALUE_TYPE cst; - - real_convert (&cst, TYPE_MODE (type), &dconstpi); - SET_REAL_EXP (&cst, REAL_EXP (&cst) - 2); - return build_real (type, cst); - } - - return NULL_TREE; -} - /* Fold function call to builtin trunc, truncf or truncl. Return NULL_TREE if no simplification can be made. */ static tree -fold_builtin_trunc (tree fndecl, tree arglist) +fold_builtin_trunc (tree exp) { + tree arglist = TREE_OPERAND (exp, 1); tree arg; if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) @@ -7286,22 +5865,23 @@ fold_builtin_trunc (tree fndecl, tree arglist) if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg)) { REAL_VALUE_TYPE r, x; - tree type = TREE_TYPE (TREE_TYPE (fndecl)); + tree type = TREE_TYPE (exp); x = TREE_REAL_CST (arg); real_trunc (&r, TYPE_MODE (type), &x); return build_real (type, r); } - return fold_trunc_transparent_mathfn (fndecl, arglist); + return fold_trunc_transparent_mathfn (exp); } /* Fold function call to builtin floor, floorf or floorl. Return NULL_TREE if no simplification can be made. */ static tree -fold_builtin_floor (tree fndecl, tree arglist) +fold_builtin_floor (tree exp) { + tree arglist = TREE_OPERAND (exp, 1); tree arg; if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) @@ -7316,7 +5896,7 @@ fold_builtin_floor (tree fndecl, tree arglist) x = TREE_REAL_CST (arg); if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math) { - tree type = TREE_TYPE (TREE_TYPE (fndecl)); + tree type = TREE_TYPE (exp); REAL_VALUE_TYPE r; real_floor (&r, TYPE_MODE (type), &x); @@ -7324,15 +5904,16 @@ fold_builtin_floor (tree fndecl, tree arglist) } } - return fold_trunc_transparent_mathfn (fndecl, arglist); + return fold_trunc_transparent_mathfn (exp); } /* Fold function call to builtin ceil, ceilf or ceill. Return NULL_TREE if no simplification can be made. */ static tree -fold_builtin_ceil (tree fndecl, tree arglist) +fold_builtin_ceil (tree exp) { + tree arglist = TREE_OPERAND (exp, 1); tree arg; if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) @@ -7347,7 +5928,7 @@ fold_builtin_ceil (tree fndecl, tree arglist) x = TREE_REAL_CST (arg); if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math) { - tree type = TREE_TYPE (TREE_TYPE (fndecl)); + tree type = TREE_TYPE (exp); REAL_VALUE_TYPE r; real_ceil (&r, TYPE_MODE (type), &x); @@ -7355,94 +5936,7 @@ fold_builtin_ceil (tree fndecl, tree arglist) } } - return fold_trunc_transparent_mathfn (fndecl, arglist); -} - -/* Fold function call to builtin round, roundf or roundl. Return - NULL_TREE if no simplification can be made. */ - -static tree -fold_builtin_round (tree fndecl, tree arglist) -{ - tree arg; - - if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return 0; - - /* Optimize round of constant value. */ - arg = TREE_VALUE (arglist); - if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg)) - { - REAL_VALUE_TYPE x; - - x = TREE_REAL_CST (arg); - if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math) - { - tree type = TREE_TYPE (TREE_TYPE (fndecl)); - REAL_VALUE_TYPE r; - - real_round (&r, TYPE_MODE (type), &x); - return build_real (type, r); - } - } - - return fold_trunc_transparent_mathfn (fndecl, arglist); -} - -/* Fold function call to builtin lround, lroundf or lroundl (or the - corresponding long long versions) and other rounding functions. - Return NULL_TREE if no simplification can be made. */ - -static tree -fold_builtin_int_roundingfn (tree fndecl, tree arglist) -{ - tree arg; - - if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return 0; - - /* Optimize lround of constant value. */ - arg = TREE_VALUE (arglist); - if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg)) - { - const REAL_VALUE_TYPE x = TREE_REAL_CST (arg); - - if (! REAL_VALUE_ISNAN (x) && ! REAL_VALUE_ISINF (x)) - { - tree itype = TREE_TYPE (TREE_TYPE (fndecl)); - tree ftype = TREE_TYPE (arg), result; - HOST_WIDE_INT hi, lo; - REAL_VALUE_TYPE r; - - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_LFLOOR): - CASE_FLT_FN (BUILT_IN_LLFLOOR): - real_floor (&r, TYPE_MODE (ftype), &x); - break; - - CASE_FLT_FN (BUILT_IN_LCEIL): - CASE_FLT_FN (BUILT_IN_LLCEIL): - real_ceil (&r, TYPE_MODE (ftype), &x); - break; - - CASE_FLT_FN (BUILT_IN_LROUND): - CASE_FLT_FN (BUILT_IN_LLROUND): - real_round (&r, TYPE_MODE (ftype), &x); - break; - - default: - gcc_unreachable (); - } - - REAL_VALUE_TO_INT (&lo, &hi, r); - result = build_int_cst_wide (NULL_TREE, lo, hi); - if (int_fits_type_p (result, itype)) - return fold_convert (itype, result); - } - } - - return fold_fixed_mathfn (fndecl, arglist); + return fold_trunc_transparent_mathfn (exp); } /* Fold function call to builtin ffs, clz, ctz, popcount and parity @@ -7450,8 +5944,10 @@ fold_builtin_int_roundingfn (tree fndecl, tree arglist) Return NULL_TREE if no simplification can be made. */ static tree -fold_builtin_bitop (tree fndecl, tree arglist) +fold_builtin_bitop (tree exp) { + tree fndecl = get_callee_fndecl (exp); + tree arglist = TREE_OPERAND (exp, 1); tree arg; if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE)) @@ -7463,7 +5959,7 @@ fold_builtin_bitop (tree fndecl, tree arglist) { HOST_WIDE_INT hi, width, result; unsigned HOST_WIDE_INT lo; - tree type; + tree type, t; type = TREE_TYPE (arg); width = TYPE_PRECISION (type); @@ -7485,7 +5981,9 @@ fold_builtin_bitop (tree fndecl, tree arglist) switch (DECL_FUNCTION_CODE (fndecl)) { - CASE_INT_FN (BUILT_IN_FFS): + case BUILT_IN_FFS: + case BUILT_IN_FFSL: + case BUILT_IN_FFSLL: if (lo != 0) result = exact_log2 (lo & -lo) + 1; else if (hi != 0) @@ -7494,7 +5992,9 @@ fold_builtin_bitop (tree fndecl, tree arglist) result = 0; break; - CASE_INT_FN (BUILT_IN_CLZ): + case BUILT_IN_CLZ: + case BUILT_IN_CLZL: + case BUILT_IN_CLZLL: if (hi != 0) result = width - floor_log2 (hi) - 1 - HOST_BITS_PER_WIDE_INT; else if (lo != 0) @@ -7503,7 +6003,9 @@ fold_builtin_bitop (tree fndecl, tree arglist) result = width; break; - CASE_INT_FN (BUILT_IN_CTZ): + case BUILT_IN_CTZ: + case BUILT_IN_CTZL: + case BUILT_IN_CTZLL: if (lo != 0) result = exact_log2 (lo & -lo); else if (hi != 0) @@ -7512,7 +6014,9 @@ fold_builtin_bitop (tree fndecl, tree arglist) result = width; break; - CASE_INT_FN (BUILT_IN_POPCOUNT): + case BUILT_IN_POPCOUNT: + case BUILT_IN_POPCOUNTL: + case BUILT_IN_POPCOUNTLL: result = 0; while (lo) result++, lo &= lo - 1; @@ -7520,7 +6024,9 @@ fold_builtin_bitop (tree fndecl, tree arglist) result++, hi &= hi - 1; break; - CASE_INT_FN (BUILT_IN_PARITY): + case BUILT_IN_PARITY: + case BUILT_IN_PARITYL: + case BUILT_IN_PARITYLL: result = 0; while (lo) result++, lo &= lo - 1; @@ -7530,10 +6036,12 @@ fold_builtin_bitop (tree fndecl, tree arglist) break; default: - gcc_unreachable (); + abort(); } - return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), result); + t = build_int_2 (result, 0); + TREE_TYPE (t) = TREE_TYPE (exp); + return t; } return NULL_TREE; @@ -7547,42 +6055,44 @@ real_dconstp (tree expr, const REAL_VALUE_TYPE *value) STRIP_NOPS (expr); return ((TREE_CODE (expr) == REAL_CST - && ! TREE_CONSTANT_OVERFLOW (expr) - && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), *value)) - || (TREE_CODE (expr) == COMPLEX_CST - && real_dconstp (TREE_REALPART (expr), value) - && real_zerop (TREE_IMAGPART (expr)))); + && ! TREE_CONSTANT_OVERFLOW (expr) + && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), *value)) + || (TREE_CODE (expr) == COMPLEX_CST + && real_dconstp (TREE_REALPART (expr), value) + && real_zerop (TREE_IMAGPART (expr)))); } /* A subroutine of fold_builtin to fold the various logarithmic - functions. EXP is the CALL_EXPR of a call to a builtin logN - function. VALUE is the base of the logN function. */ + functions. EXP is the CALL_EXPR of a call to a builtin log* + function. VALUE is the base of the log* function. */ static tree -fold_builtin_logarithm (tree fndecl, tree arglist, - const REAL_VALUE_TYPE *value) +fold_builtin_logarithm (tree exp, const REAL_VALUE_TYPE *value) { + tree arglist = TREE_OPERAND (exp, 1); + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) { + tree fndecl = get_callee_fndecl (exp); tree type = TREE_TYPE (TREE_TYPE (fndecl)); tree arg = TREE_VALUE (arglist); const enum built_in_function fcode = builtin_mathfn_code (arg); - - /* Optimize logN(1.0) = 0.0. */ + + /* Optimize log*(1.0) = 0.0. */ if (real_onep (arg)) return build_real (type, dconst0); /* Optimize logN(N) = 1.0. If N can't be truncated to MODE - exactly, then only do this if flag_unsafe_math_optimizations. */ + exactly, then only do this if flag_unsafe_math_optimizations. */ if (exact_real_truncate (TYPE_MODE (type), value) || flag_unsafe_math_optimizations) - { + { const REAL_VALUE_TYPE value_truncate = real_value_truncate (TYPE_MODE (type), *value); if (real_dconstp (arg, &value_truncate)) return build_real (type, dconst1); } - + /* Special case, optimize logN(expN(x)) = x. */ if (flag_unsafe_math_optimizations && ((value == &dconste @@ -7593,47 +6103,64 @@ fold_builtin_logarithm (tree fndecl, tree arglist, && (fcode == BUILT_IN_EXP2 || fcode == BUILT_IN_EXP2F || fcode == BUILT_IN_EXP2L)) - || (value == &dconst10 && (BUILTIN_EXP10_P (fcode))))) - return fold_convert (type, TREE_VALUE (TREE_OPERAND (arg, 1))); - - /* Optimize logN(func()) for various exponential functions. We - want to determine the value "x" and the power "exponent" in - order to transform logN(x**exponent) into exponent*logN(x). */ + || (value == &dconst10 + && (fcode == BUILT_IN_EXP10 + || fcode == BUILT_IN_EXP10F + || fcode == BUILT_IN_EXP10L)))) + return convert (type, TREE_VALUE (TREE_OPERAND (arg, 1))); + + /* Optimize log*(func()) for various exponential functions. We + want to determine the value "x" and the power "exponent" in + order to transform logN(x**exponent) into exponent*logN(x). */ if (flag_unsafe_math_optimizations) - { + { tree exponent = 0, x = 0; - + switch (fcode) { - CASE_FLT_FN (BUILT_IN_EXP): + case BUILT_IN_EXP: + case BUILT_IN_EXPF: + case BUILT_IN_EXPL: /* Prepare to do logN(exp(exponent) -> exponent*logN(e). */ x = build_real (type, real_value_truncate (TYPE_MODE (type), dconste)); exponent = TREE_VALUE (TREE_OPERAND (arg, 1)); break; - CASE_FLT_FN (BUILT_IN_EXP2): + case BUILT_IN_EXP2: + case BUILT_IN_EXP2F: + case BUILT_IN_EXP2L: /* Prepare to do logN(exp2(exponent) -> exponent*logN(2). */ x = build_real (type, dconst2); exponent = TREE_VALUE (TREE_OPERAND (arg, 1)); break; - CASE_FLT_FN (BUILT_IN_EXP10): - CASE_FLT_FN (BUILT_IN_POW10): + case BUILT_IN_EXP10: + case BUILT_IN_EXP10F: + case BUILT_IN_EXP10L: + case BUILT_IN_POW10: + case BUILT_IN_POW10F: + case BUILT_IN_POW10L: /* Prepare to do logN(exp10(exponent) -> exponent*logN(10). */ x = build_real (type, dconst10); exponent = TREE_VALUE (TREE_OPERAND (arg, 1)); break; - CASE_FLT_FN (BUILT_IN_SQRT): + case BUILT_IN_SQRT: + case BUILT_IN_SQRTF: + case BUILT_IN_SQRTL: /* Prepare to do logN(sqrt(x) -> 0.5*logN(x). */ x = TREE_VALUE (TREE_OPERAND (arg, 1)); exponent = build_real (type, dconsthalf); break; - CASE_FLT_FN (BUILT_IN_CBRT): + case BUILT_IN_CBRT: + case BUILT_IN_CBRTF: + case BUILT_IN_CBRTL: /* Prepare to do logN(cbrt(x) -> (1/3)*logN(x). */ x = TREE_VALUE (TREE_OPERAND (arg, 1)); exponent = build_real (type, real_value_truncate (TYPE_MODE (type), dconstthird)); break; - CASE_FLT_FN (BUILT_IN_POW): + case BUILT_IN_POW: + case BUILT_IN_POWF: + case BUILT_IN_POWL: /* Prepare to do logN(pow(x,exponent) -> exponent*logN(x). */ x = TREE_VALUE (TREE_OPERAND (arg, 1)); exponent = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1))); @@ -7648,212 +6175,26 @@ fold_builtin_logarithm (tree fndecl, tree arglist, tree logfn; arglist = build_tree_list (NULL_TREE, x); logfn = build_function_call_expr (fndecl, arglist); - return fold_build2 (MULT_EXPR, type, exponent, logfn); + return fold (build (MULT_EXPR, type, exponent, logfn)); } } } return 0; } - -/* Fold a builtin function call to pow, powf, or powl. Return - NULL_TREE if no simplification can be made. */ -static tree -fold_builtin_pow (tree fndecl, tree arglist, tree type) -{ - tree arg0 = TREE_VALUE (arglist); - tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - - if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - /* Optimize pow(1.0,y) = 1.0. */ - if (real_onep (arg0)) - return omit_one_operand (type, build_real (type, dconst1), arg1); - - if (TREE_CODE (arg1) == REAL_CST - && ! TREE_CONSTANT_OVERFLOW (arg1)) - { - REAL_VALUE_TYPE cint; - REAL_VALUE_TYPE c; - HOST_WIDE_INT n; - - c = TREE_REAL_CST (arg1); - - /* Optimize pow(x,0.0) = 1.0. */ - if (REAL_VALUES_EQUAL (c, dconst0)) - return omit_one_operand (type, build_real (type, dconst1), - arg0); - - /* Optimize pow(x,1.0) = x. */ - if (REAL_VALUES_EQUAL (c, dconst1)) - return arg0; - - /* Optimize pow(x,-1.0) = 1.0/x. */ - if (REAL_VALUES_EQUAL (c, dconstm1)) - return fold_build2 (RDIV_EXPR, type, - build_real (type, dconst1), arg0); - - /* Optimize pow(x,0.5) = sqrt(x). */ - if (flag_unsafe_math_optimizations - && REAL_VALUES_EQUAL (c, dconsthalf)) - { - tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT); - - if (sqrtfn != NULL_TREE) - { - tree arglist = build_tree_list (NULL_TREE, arg0); - return build_function_call_expr (sqrtfn, arglist); - } - } - - /* Check for an integer exponent. */ - n = real_to_integer (&c); - real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0); - if (real_identical (&c, &cint)) - { - /* Attempt to evaluate pow at compile-time. */ - if (TREE_CODE (arg0) == REAL_CST - && ! TREE_CONSTANT_OVERFLOW (arg0)) - { - REAL_VALUE_TYPE x; - bool inexact; - - x = TREE_REAL_CST (arg0); - inexact = real_powi (&x, TYPE_MODE (type), &x, n); - if (flag_unsafe_math_optimizations || !inexact) - return build_real (type, x); - } - - /* Strip sign ops from even integer powers. */ - if ((n & 1) == 0 && flag_unsafe_math_optimizations) - { - tree narg0 = fold_strip_sign_ops (arg0); - if (narg0) - { - arglist = build_tree_list (NULL_TREE, arg1); - arglist = tree_cons (NULL_TREE, narg0, arglist); - return build_function_call_expr (fndecl, arglist); - } - } - } - } - - if (flag_unsafe_math_optimizations) - { - const enum built_in_function fcode = builtin_mathfn_code (arg0); - - /* Optimize pow(expN(x),y) = expN(x*y). */ - if (BUILTIN_EXPONENT_P (fcode)) - { - tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); - tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1)); - arg = fold_build2 (MULT_EXPR, type, arg, arg1); - arglist = build_tree_list (NULL_TREE, arg); - return build_function_call_expr (expfn, arglist); - } - - /* Optimize pow(sqrt(x),y) = pow(x,y*0.5). */ - if (BUILTIN_SQRT_P (fcode)) - { - tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1)); - tree narg1 = fold_build2 (MULT_EXPR, type, arg1, - build_real (type, dconsthalf)); - - arglist = tree_cons (NULL_TREE, narg0, - build_tree_list (NULL_TREE, narg1)); - return build_function_call_expr (fndecl, arglist); - } - - /* Optimize pow(cbrt(x),y) = pow(x,y/3) iff x is nonnegative. */ - if (BUILTIN_CBRT_P (fcode)) - { - tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1)); - if (tree_expr_nonnegative_p (arg)) - { - const REAL_VALUE_TYPE dconstroot - = real_value_truncate (TYPE_MODE (type), dconstthird); - tree narg1 = fold_build2 (MULT_EXPR, type, arg1, - build_real (type, dconstroot)); - arglist = tree_cons (NULL_TREE, arg, - build_tree_list (NULL_TREE, narg1)); - return build_function_call_expr (fndecl, arglist); - } - } - - /* Optimize pow(pow(x,y),z) = pow(x,y*z). */ - if (fcode == BUILT_IN_POW || fcode == BUILT_IN_POWF - || fcode == BUILT_IN_POWL) - { - tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); - tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1))); - tree narg1 = fold_build2 (MULT_EXPR, type, arg01, arg1); - arglist = tree_cons (NULL_TREE, arg00, - build_tree_list (NULL_TREE, narg1)); - return build_function_call_expr (fndecl, arglist); - } - } - - return NULL_TREE; -} - -/* Fold a builtin function call to powi, powif, or powil. Return - NULL_TREE if no simplification can be made. */ -static tree -fold_builtin_powi (tree fndecl ATTRIBUTE_UNUSED, tree arglist, tree type) -{ - tree arg0 = TREE_VALUE (arglist); - tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - - if (!validate_arglist (arglist, REAL_TYPE, INTEGER_TYPE, VOID_TYPE)) - return NULL_TREE; - - /* Optimize pow(1.0,y) = 1.0. */ - if (real_onep (arg0)) - return omit_one_operand (type, build_real (type, dconst1), arg1); - - if (host_integerp (arg1, 0)) - { - HOST_WIDE_INT c = TREE_INT_CST_LOW (arg1); - - /* Evaluate powi at compile-time. */ - if (TREE_CODE (arg0) == REAL_CST - && ! TREE_CONSTANT_OVERFLOW (arg0)) - { - REAL_VALUE_TYPE x; - x = TREE_REAL_CST (arg0); - real_powi (&x, TYPE_MODE (type), &x, c); - return build_real (type, x); - } - - /* Optimize pow(x,0) = 1.0. */ - if (c == 0) - return omit_one_operand (type, build_real (type, dconst1), - arg0); - - /* Optimize pow(x,1) = x. */ - if (c == 1) - return arg0; - - /* Optimize pow(x,-1) = 1.0/x. */ - if (c == -1) - return fold_build2 (RDIV_EXPR, type, - build_real (type, dconst1), arg0); - } - - return NULL_TREE; -} - + /* A subroutine of fold_builtin to fold the various exponent functions. EXP is the CALL_EXPR of a call to a builtin function. VALUE is the value which will be raised to a power. */ static tree -fold_builtin_exponent (tree fndecl, tree arglist, - const REAL_VALUE_TYPE *value) +fold_builtin_exponent (tree exp, const REAL_VALUE_TYPE *value) { + tree arglist = TREE_OPERAND (exp, 1); + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) { + tree fndecl = get_callee_fndecl (exp); tree type = TREE_TYPE (TREE_TYPE (fndecl)); tree arg = TREE_VALUE (arglist); @@ -7863,7 +6204,7 @@ fold_builtin_exponent (tree fndecl, tree arglist, /* Optimize expN(1.0) = N. */ if (real_onep (arg)) - { + { REAL_VALUE_TYPE cst; real_convert (&cst, TYPE_MODE (type), value); @@ -7874,7 +6215,7 @@ fold_builtin_exponent (tree fndecl, tree arglist, if (flag_unsafe_math_optimizations && TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg)) - { + { REAL_VALUE_TYPE cint; REAL_VALUE_TYPE c; HOST_WIDE_INT n; @@ -7894,7 +6235,7 @@ fold_builtin_exponent (tree fndecl, tree arglist, /* Optimize expN(logN(x)) = x. */ if (flag_unsafe_math_optimizations) - { + { const enum built_in_function fcode = builtin_mathfn_code (arg); if ((value == &dconste @@ -7909,142 +6250,52 @@ fold_builtin_exponent (tree fndecl, tree arglist, && (fcode == BUILT_IN_LOG10 || fcode == BUILT_IN_LOG10F || fcode == BUILT_IN_LOG10L))) - return fold_convert (type, TREE_VALUE (TREE_OPERAND (arg, 1))); + return convert (type, TREE_VALUE (TREE_OPERAND (arg, 1))); } } return 0; } -/* Return true if VAR is a VAR_DECL or a component thereof. */ - -static bool -var_decl_component_p (tree var) -{ - tree inner = var; - while (handled_component_p (inner)) - inner = TREE_OPERAND (inner, 0); - return SSA_VAR_P (inner); -} - -/* Fold function call to builtin memset. Return +/* Fold function call to builtin memcpy. Return NULL_TREE if no simplification can be made. */ static tree -fold_builtin_memset (tree arglist, tree type, bool ignore) +fold_builtin_memcpy (tree exp) { - tree dest, c, len, var, ret; - unsigned HOST_WIDE_INT length, cval; + tree arglist = TREE_OPERAND (exp, 1); + tree dest, src, len; if (!validate_arglist (arglist, - POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)) + POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; dest = TREE_VALUE (arglist); - c = TREE_VALUE (TREE_CHAIN (arglist)); + src = TREE_VALUE (TREE_CHAIN (arglist)); len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - if (! host_integerp (len, 1)) - return 0; - /* If the LEN parameter is zero, return DEST. */ if (integer_zerop (len)) - return omit_one_operand (type, dest, c); - - if (! host_integerp (c, 1) || TREE_SIDE_EFFECTS (dest)) - return 0; - - var = dest; - STRIP_NOPS (var); - if (TREE_CODE (var) != ADDR_EXPR) - return 0; - - var = TREE_OPERAND (var, 0); - if (TREE_THIS_VOLATILE (var)) - return 0; - - if (!INTEGRAL_TYPE_P (TREE_TYPE (var)) - && !POINTER_TYPE_P (TREE_TYPE (var))) - return 0; - - if (! var_decl_component_p (var)) - return 0; - - length = tree_low_cst (len, 1); - if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (var))) != length - || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT - < (int) length) - return 0; - - if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT) - return 0; - - if (integer_zerop (c)) - cval = 0; - else - { - if (CHAR_BIT != 8 || BITS_PER_UNIT != 8 || HOST_BITS_PER_WIDE_INT > 64) - return 0; + return omit_one_operand (TREE_TYPE (exp), dest, src); - cval = tree_low_cst (c, 1); - cval &= 0xff; - cval |= cval << 8; - cval |= cval << 16; - cval |= (cval << 31) << 1; - } - - ret = build_int_cst_type (TREE_TYPE (var), cval); - ret = build2 (MODIFY_EXPR, TREE_TYPE (var), var, ret); - if (ignore) - return ret; + /* If SRC and DEST are the same (and not volatile), return DEST. */ + if (operand_equal_p (src, dest, 0)) + return omit_one_operand (TREE_TYPE (exp), dest, len); - return omit_one_operand (type, dest, ret); + return 0; } -/* Fold function call to builtin memset. Return +/* Fold function call to builtin mempcpy. Return NULL_TREE if no simplification can be made. */ static tree -fold_builtin_bzero (tree arglist, bool ignore) -{ - tree dest, size, newarglist; - - if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return 0; - - if (!ignore) - return 0; - - dest = TREE_VALUE (arglist); - size = TREE_VALUE (TREE_CHAIN (arglist)); - - /* New argument list transforming bzero(ptr x, int y) to - memset(ptr x, int 0, size_t y). This is done this way - so that if it isn't expanded inline, we fallback to - calling bzero instead of memset. */ - - newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size)); - newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist); - newarglist = tree_cons (NULL_TREE, dest, newarglist); - return fold_builtin_memset (newarglist, void_type_node, ignore); -} - -/* Fold function call to builtin mem{{,p}cpy,move}. Return - NULL_TREE if no simplification can be made. - If ENDP is 0, return DEST (like memcpy). - If ENDP is 1, return DEST+LEN (like mempcpy). - If ENDP is 2, return DEST+LEN-1 (like stpcpy). - If ENDP is 3, return DEST, additionally *SRC and *DEST may overlap - (memmove). */ - -static tree -fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp) +fold_builtin_mempcpy (tree exp) { - tree dest, src, len, destvar, srcvar, expr; - unsigned HOST_WIDE_INT length; + tree arglist = TREE_OPERAND (exp, 1); + tree dest, src, len; - if (! validate_arglist (arglist, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, + POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; dest = TREE_VALUE (arglist); @@ -8053,133 +6304,55 @@ fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp) /* If the LEN parameter is zero, return DEST. */ if (integer_zerop (len)) - return omit_one_operand (type, dest, src); + return omit_one_operand (TREE_TYPE (exp), dest, src); - /* If SRC and DEST are the same (and not volatile), return - DEST{,+LEN,+LEN-1}. */ + /* If SRC and DEST are the same (and not volatile), return DEST+LEN. */ if (operand_equal_p (src, dest, 0)) - expr = len; - else { - if (! host_integerp (len, 1)) - return 0; - - if (TREE_SIDE_EFFECTS (dest) || TREE_SIDE_EFFECTS (src)) - return 0; - - destvar = dest; - STRIP_NOPS (destvar); - if (TREE_CODE (destvar) != ADDR_EXPR) - return 0; - - destvar = TREE_OPERAND (destvar, 0); - if (TREE_THIS_VOLATILE (destvar)) - return 0; - - if (!INTEGRAL_TYPE_P (TREE_TYPE (destvar)) - && !POINTER_TYPE_P (TREE_TYPE (destvar)) - && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (destvar))) - return 0; - - if (! var_decl_component_p (destvar)) - return 0; - - srcvar = src; - STRIP_NOPS (srcvar); - if (TREE_CODE (srcvar) != ADDR_EXPR) - return 0; - - srcvar = TREE_OPERAND (srcvar, 0); - if (TREE_THIS_VOLATILE (srcvar)) - return 0; - - if (!INTEGRAL_TYPE_P (TREE_TYPE (srcvar)) - && !POINTER_TYPE_P (TREE_TYPE (srcvar)) - && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (srcvar))) - return 0; - - if (! var_decl_component_p (srcvar)) - return 0; - - length = tree_low_cst (len, 1); - if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (destvar))) != length - || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT - < (int) length - || GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (srcvar))) != length - || get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT - < (int) length) - return 0; - - if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar)) - || POINTER_TYPE_P (TREE_TYPE (srcvar))) - && (INTEGRAL_TYPE_P (TREE_TYPE (destvar)) - || POINTER_TYPE_P (TREE_TYPE (destvar)))) - expr = fold_convert (TREE_TYPE (destvar), srcvar); - else - expr = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (destvar), srcvar); - expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, expr); + tree temp = convert (TREE_TYPE (dest), len); + temp = fold (build (PLUS_EXPR, TREE_TYPE (dest), dest, len)); + return convert (TREE_TYPE (exp), temp); } - if (ignore) - return expr; - - if (endp == 0 || endp == 3) - return omit_one_operand (type, dest, expr); - - if (expr == len) - expr = 0; - - if (endp == 2) - len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len, - ssize_int (1)); - - len = fold_convert (TREE_TYPE (dest), len); - dest = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len); - dest = fold_convert (type, dest); - if (expr) - dest = omit_one_operand (type, dest, expr); - return dest; + return 0; } -/* Fold function call to builtin bcopy. Return NULL_TREE if no - simplification can be made. */ +/* Fold function call to builtin memmove. Return + NULL_TREE if no simplification can be made. */ static tree -fold_builtin_bcopy (tree arglist, bool ignore) +fold_builtin_memmove (tree exp) { - tree src, dest, size, newarglist; + tree arglist = TREE_OPERAND (exp, 1); + tree dest, src, len; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; - if (! ignore) - return 0; - - src = TREE_VALUE (arglist); - dest = TREE_VALUE (TREE_CHAIN (arglist)); - size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + dest = TREE_VALUE (arglist); + src = TREE_VALUE (TREE_CHAIN (arglist)); + len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - /* New argument list transforming bcopy(ptr x, ptr y, int z) to - memmove(ptr y, ptr x, size_t z). This is done this way - so that if it isn't expanded inline, we fallback to - calling bcopy instead of memmove. */ + /* If the LEN parameter is zero, return DEST. */ + if (integer_zerop (len)) + return omit_one_operand (TREE_TYPE (exp), dest, src); - newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size)); - newarglist = tree_cons (NULL_TREE, src, newarglist); - newarglist = tree_cons (NULL_TREE, dest, newarglist); + /* If SRC and DEST are the same (and not volatile), return DEST. */ + if (operand_equal_p (src, dest, 0)) + return omit_one_operand (TREE_TYPE (exp), dest, len); - return fold_builtin_memory_op (newarglist, void_type_node, true, /*endp=*/3); + return 0; } -/* Fold function call to builtin strcpy. If LEN is not NULL, it represents - the length of the string to be copied. Return NULL_TREE if no - simplification can be made. */ +/* Fold function call to builtin strcpy. Return + NULL_TREE if no simplification can be made. */ -tree -fold_builtin_strcpy (tree fndecl, tree arglist, tree len) +static tree +fold_builtin_strcpy (tree exp) { - tree dest, src, fn; + tree arglist = TREE_OPERAND (exp, 1); + tree dest, src; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) @@ -8190,38 +6363,19 @@ fold_builtin_strcpy (tree fndecl, tree arglist, tree len) /* If SRC and DEST are the same (and not volatile), return DEST. */ if (operand_equal_p (src, dest, 0)) - return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), dest); - - if (optimize_size) - return 0; - - fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; - if (!fn) - return 0; - - if (!len) - { - len = c_strlen (src, 1); - if (! len || TREE_SIDE_EFFECTS (len)) - return 0; - } + return convert (TREE_TYPE (exp), dest); - len = size_binop (PLUS_EXPR, len, ssize_int (1)); - arglist = build_tree_list (NULL_TREE, len); - arglist = tree_cons (NULL_TREE, src, arglist); - arglist = tree_cons (NULL_TREE, dest, arglist); - return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), - build_function_call_expr (fn, arglist)); + return 0; } -/* Fold function call to builtin strncpy. If SLEN is not NULL, it represents - the length of the source string. Return NULL_TREE if no simplification - can be made. */ +/* Fold function call to builtin strncpy. Return + NULL_TREE if no simplification can be made. */ -tree -fold_builtin_strncpy (tree fndecl, tree arglist, tree slen) +static tree +fold_builtin_strncpy (tree exp) { - tree dest, src, len, fn; + tree arglist = TREE_OPERAND (exp, 1); + tree dest, src, len; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) @@ -8233,44 +6387,19 @@ fold_builtin_strncpy (tree fndecl, tree arglist, tree slen) /* If the LEN parameter is zero, return DEST. */ if (integer_zerop (len)) - return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src); + return omit_one_operand (TREE_TYPE (exp), dest, src); - /* We can't compare slen with len as constants below if len is not a - constant. */ - if (len == 0 || TREE_CODE (len) != INTEGER_CST) - return 0; - - if (!slen) - slen = c_strlen (src, 1); - - /* Now, we must be passed a constant src ptr parameter. */ - if (slen == 0 || TREE_CODE (slen) != INTEGER_CST) - return 0; - - slen = size_binop (PLUS_EXPR, slen, ssize_int (1)); - - /* We do not support simplification of this case, though we do - support it when expanding trees into RTL. */ - /* FIXME: generate a call to __builtin_memset. */ - if (tree_int_cst_lt (slen, len)) - return 0; - - /* OK transform into builtin memcpy. */ - fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; - if (!fn) - return 0; - return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), - build_function_call_expr (fn, arglist)); + return 0; } /* Fold function call to builtin memcmp. Return NULL_TREE if no simplification can be made. */ static tree -fold_builtin_memcmp (tree arglist) +fold_builtin_memcmp (tree exp) { + tree arglist = TREE_OPERAND (exp, 1); tree arg1, arg2, len; - const char *p1, *p2; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) @@ -8282,50 +6411,14 @@ fold_builtin_memcmp (tree arglist) /* If the LEN parameter is zero, return zero. */ if (integer_zerop (len)) - return omit_two_operands (integer_type_node, integer_zero_node, - arg1, arg2); - - /* If ARG1 and ARG2 are the same (and not volatile), return zero. */ - if (operand_equal_p (arg1, arg2, 0)) - return omit_one_operand (integer_type_node, integer_zero_node, len); - - p1 = c_getstr (arg1); - p2 = c_getstr (arg2); - - /* If all arguments are constant, and the value of len is not greater - than the lengths of arg1 and arg2, evaluate at compile-time. */ - if (host_integerp (len, 1) && p1 && p2 - && compare_tree_int (len, strlen (p1) + 1) <= 0 - && compare_tree_int (len, strlen (p2) + 1) <= 0) { - const int r = memcmp (p1, p2, tree_low_cst (len, 1)); - - if (r > 0) - return integer_one_node; - else if (r < 0) - return integer_minus_one_node; - else - return integer_zero_node; + tree temp = omit_one_operand (TREE_TYPE (exp), integer_zero_node, arg2); + return omit_one_operand (TREE_TYPE (exp), temp, arg1); } - /* If len parameter is one, return an expression corresponding to - (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */ - if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1) - { - tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); - tree cst_uchar_ptr_node - = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true); - - tree ind1 = fold_convert (integer_type_node, - build1 (INDIRECT_REF, cst_uchar_node, - fold_convert (cst_uchar_ptr_node, - arg1))); - tree ind2 = fold_convert (integer_type_node, - build1 (INDIRECT_REF, cst_uchar_node, - fold_convert (cst_uchar_ptr_node, - arg2))); - return fold_build2 (MINUS_EXPR, integer_type_node, ind1, ind2); - } + /* If ARG1 and ARG2 are the same (and not volatile), return zero. */ + if (operand_equal_p (arg1, arg2, 0)) + return omit_one_operand (TREE_TYPE (exp), integer_zero_node, len); return 0; } @@ -8334,12 +6427,14 @@ fold_builtin_memcmp (tree arglist) NULL_TREE if no simplification can be made. */ static tree -fold_builtin_strcmp (tree arglist) +fold_builtin_strcmp (tree exp) { + tree arglist = TREE_OPERAND (exp, 1); tree arg1, arg2; const char *p1, *p2; - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, + POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; arg1 = TREE_VALUE (arglist); @@ -8347,47 +6442,22 @@ fold_builtin_strcmp (tree arglist) /* If ARG1 and ARG2 are the same (and not volatile), return zero. */ if (operand_equal_p (arg1, arg2, 0)) - return integer_zero_node; + return convert (TREE_TYPE (exp), integer_zero_node); p1 = c_getstr (arg1); p2 = c_getstr (arg2); if (p1 && p2) { + tree temp; const int i = strcmp (p1, p2); if (i < 0) - return integer_minus_one_node; + temp = integer_minus_one_node; else if (i > 0) - return integer_one_node; + temp = integer_one_node; else - return integer_zero_node; - } - - /* If the second arg is "", return *(const unsigned char*)arg1. */ - if (p2 && *p2 == '\0') - { - tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); - tree cst_uchar_ptr_node - = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true); - - return fold_convert (integer_type_node, - build1 (INDIRECT_REF, cst_uchar_node, - fold_convert (cst_uchar_ptr_node, - arg1))); - } - - /* If the first arg is "", return -*(const unsigned char*)arg2. */ - if (p1 && *p1 == '\0') - { - tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); - tree cst_uchar_ptr_node - = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true); - - tree temp = fold_convert (integer_type_node, - build1 (INDIRECT_REF, cst_uchar_node, - fold_convert (cst_uchar_ptr_node, - arg2))); - return fold_build1 (NEGATE_EXPR, integer_type_node, temp); + temp = integer_zero_node; + return convert (TREE_TYPE (exp), temp); } return 0; @@ -8397,8 +6467,9 @@ fold_builtin_strcmp (tree arglist) NULL_TREE if no simplification can be made. */ static tree -fold_builtin_strncmp (tree arglist) +fold_builtin_strncmp (tree exp) { + tree arglist = TREE_OPERAND (exp, 1); tree arg1, arg2, len; const char *p1, *p2; @@ -8412,764 +6483,455 @@ fold_builtin_strncmp (tree arglist) /* If the LEN parameter is zero, return zero. */ if (integer_zerop (len)) - return omit_two_operands (integer_type_node, integer_zero_node, - arg1, arg2); + { + tree temp = omit_one_operand (TREE_TYPE (exp), integer_zero_node, arg2); + return omit_one_operand (TREE_TYPE (exp), temp, arg1); + } /* If ARG1 and ARG2 are the same (and not volatile), return zero. */ if (operand_equal_p (arg1, arg2, 0)) - return omit_one_operand (integer_type_node, integer_zero_node, len); + return omit_one_operand (TREE_TYPE (exp), integer_zero_node, len); p1 = c_getstr (arg1); p2 = c_getstr (arg2); if (host_integerp (len, 1) && p1 && p2) { + tree temp; const int i = strncmp (p1, p2, tree_low_cst (len, 1)); - if (i > 0) - return integer_one_node; - else if (i < 0) - return integer_minus_one_node; + if (i < 0) + temp = integer_minus_one_node; + else if (i > 0) + temp = integer_one_node; else - return integer_zero_node; - } - - /* If the second arg is "", and the length is greater than zero, - return *(const unsigned char*)arg1. */ - if (p2 && *p2 == '\0' - && TREE_CODE (len) == INTEGER_CST - && tree_int_cst_sgn (len) == 1) - { - tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); - tree cst_uchar_ptr_node - = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true); - - return fold_convert (integer_type_node, - build1 (INDIRECT_REF, cst_uchar_node, - fold_convert (cst_uchar_ptr_node, - arg1))); - } - - /* If the first arg is "", and the length is greater than zero, - return -*(const unsigned char*)arg2. */ - if (p1 && *p1 == '\0' - && TREE_CODE (len) == INTEGER_CST - && tree_int_cst_sgn (len) == 1) - { - tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); - tree cst_uchar_ptr_node - = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true); - - tree temp = fold_convert (integer_type_node, - build1 (INDIRECT_REF, cst_uchar_node, - fold_convert (cst_uchar_ptr_node, - arg2))); - return fold_build1 (NEGATE_EXPR, integer_type_node, temp); - } - - /* If len parameter is one, return an expression corresponding to - (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */ - if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1) - { - tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); - tree cst_uchar_ptr_node - = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true); - - tree ind1 = fold_convert (integer_type_node, - build1 (INDIRECT_REF, cst_uchar_node, - fold_convert (cst_uchar_ptr_node, - arg1))); - tree ind2 = fold_convert (integer_type_node, - build1 (INDIRECT_REF, cst_uchar_node, - fold_convert (cst_uchar_ptr_node, - arg2))); - return fold_build2 (MINUS_EXPR, integer_type_node, ind1, ind2); + temp = integer_zero_node; + return convert (TREE_TYPE (exp), temp); } return 0; } -/* Fold function call to builtin signbit, signbitf or signbitl. Return - NULL_TREE if no simplification can be made. */ +/* Used by constant folding to eliminate some builtin calls early. EXP is + the CALL_EXPR of a call to a builtin function. */ -static tree -fold_builtin_signbit (tree fndecl, tree arglist) +tree +fold_builtin (tree exp) { + tree fndecl = get_callee_fndecl (exp); + tree arglist = TREE_OPERAND (exp, 1); tree type = TREE_TYPE (TREE_TYPE (fndecl)); - tree arg, temp; - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - arg = TREE_VALUE (arglist); - - /* If ARG is a compile-time constant, determine the result. */ - if (TREE_CODE (arg) == REAL_CST - && !TREE_CONSTANT_OVERFLOW (arg)) - { - REAL_VALUE_TYPE c; - - c = TREE_REAL_CST (arg); - temp = REAL_VALUE_NEGATIVE (c) ? integer_one_node : integer_zero_node; - return fold_convert (type, temp); - } - - /* If ARG is non-negative, the result is always zero. */ - if (tree_expr_nonnegative_p (arg)) - return omit_one_operand (type, integer_zero_node, arg); - - /* If ARG's format doesn't have signed zeros, return "arg < 0.0". */ - if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg)))) - return fold_build2 (LT_EXPR, type, arg, - build_real (TREE_TYPE (arg), dconst0)); - - return NULL_TREE; -} - -/* Fold function call to builtin copysign, copysignf or copysignl. - Return NULL_TREE if no simplification can be made. */ - -static tree -fold_builtin_copysign (tree fndecl, tree arglist, tree type) -{ - tree arg1, arg2, tem; - - if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - arg1 = TREE_VALUE (arglist); - arg2 = TREE_VALUE (TREE_CHAIN (arglist)); - - /* copysign(X,X) is X. */ - if (operand_equal_p (arg1, arg2, 0)) - return fold_convert (type, arg1); - - /* If ARG1 and ARG2 are compile-time constants, determine the result. */ - if (TREE_CODE (arg1) == REAL_CST - && TREE_CODE (arg2) == REAL_CST - && !TREE_CONSTANT_OVERFLOW (arg1) - && !TREE_CONSTANT_OVERFLOW (arg2)) - { - REAL_VALUE_TYPE c1, c2; - - c1 = TREE_REAL_CST (arg1); - c2 = TREE_REAL_CST (arg2); - /* c1.sign := c2.sign. */ - real_copysign (&c1, &c2); - return build_real (type, c1); - } - - /* copysign(X, Y) is fabs(X) when Y is always non-negative. - Remember to evaluate Y for side-effects. */ - if (tree_expr_nonnegative_p (arg2)) - return omit_one_operand (type, - fold_build1 (ABS_EXPR, type, arg1), - arg2); - - /* Strip sign changing operations for the first argument. */ - tem = fold_strip_sign_ops (arg1); - if (tem) - { - arglist = tree_cons (NULL_TREE, tem, TREE_CHAIN (arglist)); - return build_function_call_expr (fndecl, arglist); - } - - return NULL_TREE; -} -/* Fold a call to builtin isascii. */ - -static tree -fold_builtin_isascii (tree arglist) -{ - if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE)) - return 0; - else - { - /* Transform isascii(c) -> ((c & ~0x7f) == 0). */ - tree arg = TREE_VALUE (arglist); - - arg = build2 (BIT_AND_EXPR, integer_type_node, arg, - build_int_cst (NULL_TREE, - ~ (unsigned HOST_WIDE_INT) 0x7f)); - arg = fold_build2 (EQ_EXPR, integer_type_node, - arg, integer_zero_node); - - if (in_gimple_form && !TREE_CONSTANT (arg)) - return NULL_TREE; - else - return arg; - } -} - -/* Fold a call to builtin toascii. */ - -static tree -fold_builtin_toascii (tree arglist) -{ - if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE)) + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) return 0; - else - { - /* Transform toascii(c) -> (c & 0x7f). */ - tree arg = TREE_VALUE (arglist); - - return fold_build2 (BIT_AND_EXPR, integer_type_node, arg, - build_int_cst (NULL_TREE, 0x7f)); - } -} -/* Fold a call to builtin isdigit. */ - -static tree -fold_builtin_isdigit (tree arglist) -{ - if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE)) - return 0; - else + switch (DECL_FUNCTION_CODE (fndecl)) { - /* Transform isdigit(c) -> (unsigned)(c) - '0' <= 9. */ - /* According to the C standard, isdigit is unaffected by locale. - However, it definitely is affected by the target character set. */ - tree arg; - unsigned HOST_WIDE_INT target_digit0 - = lang_hooks.to_target_charset ('0'); - - if (target_digit0 == 0) - return NULL_TREE; - - arg = fold_convert (unsigned_type_node, TREE_VALUE (arglist)); - arg = build2 (MINUS_EXPR, unsigned_type_node, arg, - build_int_cst (unsigned_type_node, target_digit0)); - arg = fold_build2 (LE_EXPR, integer_type_node, arg, - build_int_cst (unsigned_type_node, 9)); - if (in_gimple_form && !TREE_CONSTANT (arg)) - return NULL_TREE; - else - return arg; - } -} - -/* Fold a call to fabs, fabsf or fabsl. */ - -static tree -fold_builtin_fabs (tree arglist, tree type) -{ - tree arg; + case BUILT_IN_CONSTANT_P: + return fold_builtin_constant_p (arglist); - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return 0; + case BUILT_IN_CLASSIFY_TYPE: + return fold_builtin_classify_type (arglist); - arg = TREE_VALUE (arglist); - arg = fold_convert (type, arg); - if (TREE_CODE (arg) == REAL_CST) - return fold_abs_const (arg, type); - return fold_build1 (ABS_EXPR, type, arg); -} + case BUILT_IN_STRLEN: + if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) + { + tree len = c_strlen (TREE_VALUE (arglist), 0); + if (len) + { + /* Convert from the internal "sizetype" type to "size_t". */ + if (size_type_node) + len = convert (size_type_node, len); + return len; + } + } + break; -/* Fold a call to abs, labs, llabs or imaxabs. */ + case BUILT_IN_FABS: + case BUILT_IN_FABSF: + case BUILT_IN_FABSL: + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return fold (build1 (ABS_EXPR, type, TREE_VALUE (arglist))); + break; -static tree -fold_builtin_abs (tree arglist, tree type) -{ - tree arg; + case BUILT_IN_CABS: + case BUILT_IN_CABSF: + case BUILT_IN_CABSL: + return fold_builtin_cabs (fndecl, arglist, type); - if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE)) - return 0; + case BUILT_IN_SQRT: + case BUILT_IN_SQRTF: + case BUILT_IN_SQRTL: + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + { + enum built_in_function fcode; + tree arg = TREE_VALUE (arglist); - arg = TREE_VALUE (arglist); - arg = fold_convert (type, arg); - if (TREE_CODE (arg) == INTEGER_CST) - return fold_abs_const (arg, type); - return fold_build1 (ABS_EXPR, type, arg); -} + /* Optimize sqrt of constant value. */ + if (TREE_CODE (arg) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (arg)) + { + REAL_VALUE_TYPE r, x; -/* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite. - EXP is the CALL_EXPR for the call. */ + x = TREE_REAL_CST (arg); + if (real_sqrt (&r, TYPE_MODE (type), &x) + || (!flag_trapping_math && !flag_errno_math)) + return build_real (type, r); + } -static tree -fold_builtin_classify (tree fndecl, tree arglist, int builtin_index) -{ - tree type = TREE_TYPE (TREE_TYPE (fndecl)); - tree arg; - REAL_VALUE_TYPE r; + /* Optimize sqrt(exp(x)) = exp(x*0.5). */ + fcode = builtin_mathfn_code (arg); + if (flag_unsafe_math_optimizations + && (fcode == BUILT_IN_EXP + || fcode == BUILT_IN_EXPF + || fcode == BUILT_IN_EXPL)) + { + tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0); + arg = fold (build (MULT_EXPR, type, + TREE_VALUE (TREE_OPERAND (arg, 1)), + build_real (type, dconsthalf))); + arglist = build_tree_list (NULL_TREE, arg); + return build_function_call_expr (expfn, arglist); + } - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - { - /* Check that we have exactly one argument. */ - if (arglist == 0) - { - error ("too few arguments to function %qs", - IDENTIFIER_POINTER (DECL_NAME (fndecl))); - return error_mark_node; - } - else if (TREE_CHAIN (arglist) != 0) - { - error ("too many arguments to function %qs", - IDENTIFIER_POINTER (DECL_NAME (fndecl))); - return error_mark_node; - } - else - { - error ("non-floating-point argument to function %qs", - IDENTIFIER_POINTER (DECL_NAME (fndecl))); - return error_mark_node; + /* Optimize sqrt(pow(x,y)) = pow(|x|,y*0.5). */ + if (flag_unsafe_math_optimizations + && (fcode == BUILT_IN_POW + || fcode == BUILT_IN_POWF + || fcode == BUILT_IN_POWL)) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0); + tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1)); + tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1))); + tree narg1; + if (!tree_expr_nonnegative_p (arg0)) + arg0 = build1 (ABS_EXPR, type, arg0); + narg1 = fold (build (MULT_EXPR, type, arg1, + build_real (type, dconsthalf))); + arglist = tree_cons (NULL_TREE, arg0, + build_tree_list (NULL_TREE, narg1)); + return build_function_call_expr (powfn, arglist); + } } - } - - arg = TREE_VALUE (arglist); - switch (builtin_index) - { - case BUILT_IN_ISINF: - if (!MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg)))) - return omit_one_operand (type, integer_zero_node, arg); + break; - if (TREE_CODE (arg) == REAL_CST) + case BUILT_IN_SIN: + case BUILT_IN_SINF: + case BUILT_IN_SINL: + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) { - r = TREE_REAL_CST (arg); - if (real_isinf (&r)) - return real_compare (GT_EXPR, &r, &dconst0) - ? integer_one_node : integer_minus_one_node; - else - return integer_zero_node; - } - - return NULL_TREE; - - case BUILT_IN_FINITE: - if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg))) - && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg)))) - return omit_one_operand (type, integer_zero_node, arg); + tree arg = TREE_VALUE (arglist); - if (TREE_CODE (arg) == REAL_CST) - { - r = TREE_REAL_CST (arg); - return real_isinf (&r) || real_isnan (&r) - ? integer_zero_node : integer_one_node; + /* Optimize sin(0.0) = 0.0. */ + if (real_zerop (arg)) + return arg; } + break; - return NULL_TREE; - - case BUILT_IN_ISNAN: - if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg)))) - return omit_one_operand (type, integer_zero_node, arg); - - if (TREE_CODE (arg) == REAL_CST) + case BUILT_IN_COS: + case BUILT_IN_COSF: + case BUILT_IN_COSL: + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) { - r = TREE_REAL_CST (arg); - return real_isnan (&r) ? integer_one_node : integer_zero_node; - } - - arg = builtin_save_expr (arg); - return fold_build2 (UNORDERED_EXPR, type, arg, arg); - - default: - gcc_unreachable (); - } -} - -/* Fold a call to an unordered comparison function such as - __builtin_isgreater(). FNDECL is the FUNCTION_DECL for the function - being called and ARGLIST is the argument list for the call. - UNORDERED_CODE and ORDERED_CODE are comparison codes that give - the opposite of the desired result. UNORDERED_CODE is used - for modes that can hold NaNs and ORDERED_CODE is used for - the rest. */ + tree arg = TREE_VALUE (arglist); -static tree -fold_builtin_unordered_cmp (tree fndecl, tree arglist, - enum tree_code unordered_code, - enum tree_code ordered_code) -{ - tree type = TREE_TYPE (TREE_TYPE (fndecl)); - enum tree_code code; - tree arg0, arg1; - tree type0, type1; - enum tree_code code0, code1; - tree cmp_type = NULL_TREE; + /* Optimize cos(0.0) = 1.0. */ + if (real_zerop (arg)) + return build_real (type, dconst1); - if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) - { - /* Check that we have exactly two arguments. */ - if (arglist == 0 || TREE_CHAIN (arglist) == 0) - { - error ("too few arguments to function %qs", - IDENTIFIER_POINTER (DECL_NAME (fndecl))); - return error_mark_node; - } - else if (TREE_CHAIN (TREE_CHAIN (arglist)) != 0) - { - error ("too many arguments to function %qs", - IDENTIFIER_POINTER (DECL_NAME (fndecl))); - return error_mark_node; + /* Optimize cos(-x) into cos(x). */ + if (TREE_CODE (arg) == NEGATE_EXPR) + { + tree arglist = build_tree_list (NULL_TREE, + TREE_OPERAND (arg, 0)); + return build_function_call_expr (fndecl, arglist); + } } - } - - arg0 = TREE_VALUE (arglist); - arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - - type0 = TREE_TYPE (arg0); - type1 = TREE_TYPE (arg1); - - code0 = TREE_CODE (type0); - code1 = TREE_CODE (type1); - - if (code0 == REAL_TYPE && code1 == REAL_TYPE) - /* Choose the wider of two real types. */ - cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1) - ? type0 : type1; - else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE) - cmp_type = type0; - else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE) - cmp_type = type1; - else - { - error ("non-floating-point argument to function %qs", - IDENTIFIER_POINTER (DECL_NAME (fndecl))); - return error_mark_node; - } - - arg0 = fold_convert (cmp_type, arg0); - arg1 = fold_convert (cmp_type, arg1); - - if (unordered_code == UNORDERED_EXPR) - { - if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg0)))) - return omit_two_operands (type, integer_zero_node, arg0, arg1); - return fold_build2 (UNORDERED_EXPR, type, arg0, arg1); - } - - code = MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg0))) ? unordered_code - : ordered_code; - return fold_build1 (TRUTH_NOT_EXPR, type, - fold_build2 (code, type, arg0, arg1)); -} - -/* Used by constant folding to simplify calls to builtin functions. EXP is - the CALL_EXPR of a call to a builtin function. IGNORE is true if the - result of the function call is ignored. This function returns NULL_TREE - if no simplification was possible. */ - -static tree -fold_builtin_1 (tree fndecl, tree arglist, bool ignore) -{ - tree type = TREE_TYPE (TREE_TYPE (fndecl)); - enum built_in_function fcode; - - if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) - return targetm.fold_builtin (fndecl, arglist, ignore); - - fcode = DECL_FUNCTION_CODE (fndecl); - switch (fcode) - { - case BUILT_IN_FPUTS: - return fold_builtin_fputs (arglist, ignore, false, NULL_TREE); - - case BUILT_IN_FPUTS_UNLOCKED: - return fold_builtin_fputs (arglist, ignore, true, NULL_TREE); - - case BUILT_IN_STRSTR: - return fold_builtin_strstr (arglist, type); - - case BUILT_IN_STRCAT: - return fold_builtin_strcat (arglist); - - case BUILT_IN_STRNCAT: - return fold_builtin_strncat (arglist); - - case BUILT_IN_STRSPN: - return fold_builtin_strspn (arglist); - - case BUILT_IN_STRCSPN: - return fold_builtin_strcspn (arglist); - - case BUILT_IN_STRCHR: - case BUILT_IN_INDEX: - return fold_builtin_strchr (arglist, type); - - case BUILT_IN_STRRCHR: - case BUILT_IN_RINDEX: - return fold_builtin_strrchr (arglist, type); - - case BUILT_IN_STRCPY: - return fold_builtin_strcpy (fndecl, arglist, NULL_TREE); - - case BUILT_IN_STRNCPY: - return fold_builtin_strncpy (fndecl, arglist, NULL_TREE); - - case BUILT_IN_STRCMP: - return fold_builtin_strcmp (arglist); - - case BUILT_IN_STRNCMP: - return fold_builtin_strncmp (arglist); - - case BUILT_IN_STRPBRK: - return fold_builtin_strpbrk (arglist, type); - - case BUILT_IN_BCMP: - case BUILT_IN_MEMCMP: - return fold_builtin_memcmp (arglist); - - case BUILT_IN_SPRINTF: - return fold_builtin_sprintf (arglist, ignore); - - case BUILT_IN_CONSTANT_P: - { - tree val; - - val = fold_builtin_constant_p (arglist); - /* Gimplification will pull the CALL_EXPR for the builtin out of - an if condition. When not optimizing, we'll not CSE it back. - To avoid link error types of regressions, return false now. */ - if (!val && !optimize) - val = integer_zero_node; - - return val; - } - - case BUILT_IN_EXPECT: - return fold_builtin_expect (arglist); - - case BUILT_IN_CLASSIFY_TYPE: - return fold_builtin_classify_type (arglist); - - case BUILT_IN_STRLEN: - return fold_builtin_strlen (arglist); - - CASE_FLT_FN (BUILT_IN_FABS): - return fold_builtin_fabs (arglist, type); - - case BUILT_IN_ABS: - case BUILT_IN_LABS: - case BUILT_IN_LLABS: - case BUILT_IN_IMAXABS: - return fold_builtin_abs (arglist, type); - - CASE_FLT_FN (BUILT_IN_CONJ): - if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE)) - return fold_build1 (CONJ_EXPR, type, TREE_VALUE (arglist)); break; - CASE_FLT_FN (BUILT_IN_CREAL): - if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE)) - return non_lvalue (fold_build1 (REALPART_EXPR, type, - TREE_VALUE (arglist))); + case BUILT_IN_EXP: + case BUILT_IN_EXPF: + case BUILT_IN_EXPL: + return fold_builtin_exponent (exp, &dconste); + case BUILT_IN_EXP2: + case BUILT_IN_EXP2F: + case BUILT_IN_EXP2L: + return fold_builtin_exponent (exp, &dconst2); + case BUILT_IN_EXP10: + case BUILT_IN_EXP10F: + case BUILT_IN_EXP10L: + case BUILT_IN_POW10: + case BUILT_IN_POW10F: + case BUILT_IN_POW10L: + return fold_builtin_exponent (exp, &dconst10); + case BUILT_IN_LOG: + case BUILT_IN_LOGF: + case BUILT_IN_LOGL: + return fold_builtin_logarithm (exp, &dconste); + break; + case BUILT_IN_LOG2: + case BUILT_IN_LOG2F: + case BUILT_IN_LOG2L: + return fold_builtin_logarithm (exp, &dconst2); + break; + case BUILT_IN_LOG10: + case BUILT_IN_LOG10F: + case BUILT_IN_LOG10L: + return fold_builtin_logarithm (exp, &dconst10); break; - CASE_FLT_FN (BUILT_IN_CIMAG): - if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE)) - return non_lvalue (fold_build1 (IMAGPART_EXPR, type, - TREE_VALUE (arglist))); + case BUILT_IN_TAN: + case BUILT_IN_TANF: + case BUILT_IN_TANL: + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + { + enum built_in_function fcode; + tree arg = TREE_VALUE (arglist); + + /* Optimize tan(0.0) = 0.0. */ + if (real_zerop (arg)) + return arg; + + /* Optimize tan(atan(x)) = x. */ + fcode = builtin_mathfn_code (arg); + if (flag_unsafe_math_optimizations + && (fcode == BUILT_IN_ATAN + || fcode == BUILT_IN_ATANF + || fcode == BUILT_IN_ATANL)) + return TREE_VALUE (TREE_OPERAND (arg, 1)); + } break; - CASE_FLT_FN (BUILT_IN_CABS): - return fold_builtin_cabs (arglist, type, fndecl); + case BUILT_IN_ATAN: + case BUILT_IN_ATANF: + case BUILT_IN_ATANL: + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + { + tree arg = TREE_VALUE (arglist); - CASE_FLT_FN (BUILT_IN_SQRT): - return fold_builtin_sqrt (arglist, type); + /* Optimize atan(0.0) = 0.0. */ + if (real_zerop (arg)) + return arg; - CASE_FLT_FN (BUILT_IN_CBRT): - return fold_builtin_cbrt (arglist, type); + /* Optimize atan(1.0) = pi/4. */ + if (real_onep (arg)) + { + REAL_VALUE_TYPE cst; - CASE_FLT_FN (BUILT_IN_SIN): - return fold_builtin_sin (arglist); + real_convert (&cst, TYPE_MODE (type), &dconstpi); + cst.exp -= 2; + return build_real (type, cst); + } + } + break; - CASE_FLT_FN (BUILT_IN_COS): - return fold_builtin_cos (arglist, type, fndecl); + case BUILT_IN_POW: + case BUILT_IN_POWF: + case BUILT_IN_POWL: + if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) + { + enum built_in_function fcode; + tree arg0 = TREE_VALUE (arglist); + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - CASE_FLT_FN (BUILT_IN_EXP): - return fold_builtin_exponent (fndecl, arglist, &dconste); + /* Optimize pow(1.0,y) = 1.0. */ + if (real_onep (arg0)) + return omit_one_operand (type, build_real (type, dconst1), arg1); - CASE_FLT_FN (BUILT_IN_EXP2): - return fold_builtin_exponent (fndecl, arglist, &dconst2); + if (TREE_CODE (arg1) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (arg1)) + { + REAL_VALUE_TYPE c; + c = TREE_REAL_CST (arg1); + + /* Optimize pow(x,0.0) = 1.0. */ + if (REAL_VALUES_EQUAL (c, dconst0)) + return omit_one_operand (type, build_real (type, dconst1), + arg0); + + /* Optimize pow(x,1.0) = x. */ + if (REAL_VALUES_EQUAL (c, dconst1)) + return arg0; + + /* Optimize pow(x,-1.0) = 1.0/x. */ + if (REAL_VALUES_EQUAL (c, dconstm1)) + return fold (build (RDIV_EXPR, type, + build_real (type, dconst1), + arg0)); + + /* Optimize pow(x,0.5) = sqrt(x). */ + if (flag_unsafe_math_optimizations + && REAL_VALUES_EQUAL (c, dconsthalf)) + { + tree sqrtfn; + + fcode = DECL_FUNCTION_CODE (fndecl); + if (fcode == BUILT_IN_POW) + sqrtfn = implicit_built_in_decls[BUILT_IN_SQRT]; + else if (fcode == BUILT_IN_POWF) + sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTF]; + else if (fcode == BUILT_IN_POWL) + sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTL]; + else + sqrtfn = NULL_TREE; - CASE_FLT_FN (BUILT_IN_EXP10): - CASE_FLT_FN (BUILT_IN_POW10): - return fold_builtin_exponent (fndecl, arglist, &dconst10); + if (sqrtfn != NULL_TREE) + { + tree arglist = build_tree_list (NULL_TREE, arg0); + return build_function_call_expr (sqrtfn, arglist); + } + } - CASE_FLT_FN (BUILT_IN_LOG): - return fold_builtin_logarithm (fndecl, arglist, &dconste); + /* Attempt to evaluate pow at compile-time. */ + if (TREE_CODE (arg0) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (arg0)) + { + REAL_VALUE_TYPE cint; + HOST_WIDE_INT n; - CASE_FLT_FN (BUILT_IN_LOG2): - return fold_builtin_logarithm (fndecl, arglist, &dconst2); + n = real_to_integer (&c); + real_from_integer (&cint, VOIDmode, n, + n < 0 ? -1 : 0, 0); + if (real_identical (&c, &cint)) + { + REAL_VALUE_TYPE x; + bool inexact; - CASE_FLT_FN (BUILT_IN_LOG10): - return fold_builtin_logarithm (fndecl, arglist, &dconst10); + x = TREE_REAL_CST (arg0); + inexact = real_powi (&x, TYPE_MODE (type), &x, n); + if (flag_unsafe_math_optimizations || !inexact) + return build_real (type, x); + } + } + } - CASE_FLT_FN (BUILT_IN_TAN): - return fold_builtin_tan (arglist); + /* Optimize pow(exp(x),y) = exp(x*y). */ + fcode = builtin_mathfn_code (arg0); + if (flag_unsafe_math_optimizations + && (fcode == BUILT_IN_EXP + || fcode == BUILT_IN_EXPF + || fcode == BUILT_IN_EXPL)) + { + tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1)); + arg = fold (build (MULT_EXPR, type, arg, arg1)); + arglist = build_tree_list (NULL_TREE, arg); + return build_function_call_expr (expfn, arglist); + } - CASE_FLT_FN (BUILT_IN_ATAN): - return fold_builtin_atan (arglist, type); + /* Optimize pow(sqrt(x),y) = pow(x,y*0.5). */ + if (flag_unsafe_math_optimizations + && (fcode == BUILT_IN_SQRT + || fcode == BUILT_IN_SQRTF + || fcode == BUILT_IN_SQRTL)) + { + tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree narg1 = fold (build (MULT_EXPR, type, arg1, + build_real (type, dconsthalf))); - CASE_FLT_FN (BUILT_IN_POW): - return fold_builtin_pow (fndecl, arglist, type); + arglist = tree_cons (NULL_TREE, narg0, + build_tree_list (NULL_TREE, narg1)); + return build_function_call_expr (fndecl, arglist); + } - CASE_FLT_FN (BUILT_IN_POWI): - return fold_builtin_powi (fndecl, arglist, type); + /* Optimize pow(pow(x,y),z) = pow(x,y*z). */ + if (flag_unsafe_math_optimizations + && (fcode == BUILT_IN_POW + || fcode == BUILT_IN_POWF + || fcode == BUILT_IN_POWL)) + { + tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1))); + tree narg1 = fold (build (MULT_EXPR, type, arg01, arg1)); + arglist = tree_cons (NULL_TREE, arg00, + build_tree_list (NULL_TREE, narg1)); + return build_function_call_expr (fndecl, arglist); + } + } + break; - CASE_FLT_FN (BUILT_IN_INF): - case BUILT_IN_INFD32: - case BUILT_IN_INFD64: - case BUILT_IN_INFD128: + case BUILT_IN_INF: + case BUILT_IN_INFF: + case BUILT_IN_INFL: return fold_builtin_inf (type, true); - CASE_FLT_FN (BUILT_IN_HUGE_VAL): + case BUILT_IN_HUGE_VAL: + case BUILT_IN_HUGE_VALF: + case BUILT_IN_HUGE_VALL: return fold_builtin_inf (type, false); - CASE_FLT_FN (BUILT_IN_NAN): - case BUILT_IN_NAND32: - case BUILT_IN_NAND64: - case BUILT_IN_NAND128: + case BUILT_IN_NAN: + case BUILT_IN_NANF: + case BUILT_IN_NANL: return fold_builtin_nan (arglist, type, true); - CASE_FLT_FN (BUILT_IN_NANS): + case BUILT_IN_NANS: + case BUILT_IN_NANSF: + case BUILT_IN_NANSL: return fold_builtin_nan (arglist, type, false); - CASE_FLT_FN (BUILT_IN_FLOOR): - return fold_builtin_floor (fndecl, arglist); - - CASE_FLT_FN (BUILT_IN_CEIL): - return fold_builtin_ceil (fndecl, arglist); - - CASE_FLT_FN (BUILT_IN_TRUNC): - return fold_builtin_trunc (fndecl, arglist); - - CASE_FLT_FN (BUILT_IN_ROUND): - return fold_builtin_round (fndecl, arglist); - - CASE_FLT_FN (BUILT_IN_NEARBYINT): - CASE_FLT_FN (BUILT_IN_RINT): - return fold_trunc_transparent_mathfn (fndecl, arglist); - - CASE_FLT_FN (BUILT_IN_LCEIL): - CASE_FLT_FN (BUILT_IN_LLCEIL): - CASE_FLT_FN (BUILT_IN_LFLOOR): - CASE_FLT_FN (BUILT_IN_LLFLOOR): - CASE_FLT_FN (BUILT_IN_LROUND): - CASE_FLT_FN (BUILT_IN_LLROUND): - return fold_builtin_int_roundingfn (fndecl, arglist); - - CASE_FLT_FN (BUILT_IN_LRINT): - CASE_FLT_FN (BUILT_IN_LLRINT): - return fold_fixed_mathfn (fndecl, arglist); - - CASE_INT_FN (BUILT_IN_FFS): - CASE_INT_FN (BUILT_IN_CLZ): - CASE_INT_FN (BUILT_IN_CTZ): - CASE_INT_FN (BUILT_IN_POPCOUNT): - CASE_INT_FN (BUILT_IN_PARITY): - return fold_builtin_bitop (fndecl, arglist); - - case BUILT_IN_MEMSET: - return fold_builtin_memset (arglist, type, ignore); + case BUILT_IN_FLOOR: + case BUILT_IN_FLOORF: + case BUILT_IN_FLOORL: + return fold_builtin_floor (exp); + + case BUILT_IN_CEIL: + case BUILT_IN_CEILF: + case BUILT_IN_CEILL: + return fold_builtin_ceil (exp); + + case BUILT_IN_TRUNC: + case BUILT_IN_TRUNCF: + case BUILT_IN_TRUNCL: + return fold_builtin_trunc (exp); + + case BUILT_IN_ROUND: + case BUILT_IN_ROUNDF: + case BUILT_IN_ROUNDL: + case BUILT_IN_NEARBYINT: + case BUILT_IN_NEARBYINTF: + case BUILT_IN_NEARBYINTL: + return fold_trunc_transparent_mathfn (exp); + + case BUILT_IN_FFS: + case BUILT_IN_FFSL: + case BUILT_IN_FFSLL: + case BUILT_IN_CLZ: + case BUILT_IN_CLZL: + case BUILT_IN_CLZLL: + case BUILT_IN_CTZ: + case BUILT_IN_CTZL: + case BUILT_IN_CTZLL: + case BUILT_IN_POPCOUNT: + case BUILT_IN_POPCOUNTL: + case BUILT_IN_POPCOUNTLL: + case BUILT_IN_PARITY: + case BUILT_IN_PARITYL: + case BUILT_IN_PARITYLL: + return fold_builtin_bitop (exp); case BUILT_IN_MEMCPY: - return fold_builtin_memory_op (arglist, type, ignore, /*endp=*/0); + return fold_builtin_memcpy (exp); case BUILT_IN_MEMPCPY: - return fold_builtin_memory_op (arglist, type, ignore, /*endp=*/1); + return fold_builtin_mempcpy (exp); case BUILT_IN_MEMMOVE: - return fold_builtin_memory_op (arglist, type, ignore, /*endp=*/3); + return fold_builtin_memmove (exp); - case BUILT_IN_BZERO: - return fold_builtin_bzero (arglist, ignore); + case BUILT_IN_STRCPY: + return fold_builtin_strcpy (exp); - case BUILT_IN_BCOPY: - return fold_builtin_bcopy (arglist, ignore); - - CASE_FLT_FN (BUILT_IN_SIGNBIT): - return fold_builtin_signbit (fndecl, arglist); - - case BUILT_IN_ISASCII: - return fold_builtin_isascii (arglist); - - case BUILT_IN_TOASCII: - return fold_builtin_toascii (arglist); - - case BUILT_IN_ISDIGIT: - return fold_builtin_isdigit (arglist); - - CASE_FLT_FN (BUILT_IN_COPYSIGN): - return fold_builtin_copysign (fndecl, arglist, type); - - CASE_FLT_FN (BUILT_IN_FINITE): - case BUILT_IN_FINITED32: - case BUILT_IN_FINITED64: - case BUILT_IN_FINITED128: - return fold_builtin_classify (fndecl, arglist, BUILT_IN_FINITE); - - CASE_FLT_FN (BUILT_IN_ISINF): - case BUILT_IN_ISINFD32: - case BUILT_IN_ISINFD64: - case BUILT_IN_ISINFD128: - return fold_builtin_classify (fndecl, arglist, BUILT_IN_ISINF); - - CASE_FLT_FN (BUILT_IN_ISNAN): - case BUILT_IN_ISNAND32: - case BUILT_IN_ISNAND64: - case BUILT_IN_ISNAND128: - return fold_builtin_classify (fndecl, arglist, BUILT_IN_ISNAN); - - case BUILT_IN_ISGREATER: - return fold_builtin_unordered_cmp (fndecl, arglist, UNLE_EXPR, LE_EXPR); - case BUILT_IN_ISGREATEREQUAL: - return fold_builtin_unordered_cmp (fndecl, arglist, UNLT_EXPR, LT_EXPR); - case BUILT_IN_ISLESS: - return fold_builtin_unordered_cmp (fndecl, arglist, UNGE_EXPR, GE_EXPR); - case BUILT_IN_ISLESSEQUAL: - return fold_builtin_unordered_cmp (fndecl, arglist, UNGT_EXPR, GT_EXPR); - case BUILT_IN_ISLESSGREATER: - return fold_builtin_unordered_cmp (fndecl, arglist, UNEQ_EXPR, EQ_EXPR); - case BUILT_IN_ISUNORDERED: - return fold_builtin_unordered_cmp (fndecl, arglist, UNORDERED_EXPR, - NOP_EXPR); - - /* We do the folding for va_start in the expander. */ - case BUILT_IN_VA_START: - break; + case BUILT_IN_STRNCPY: + return fold_builtin_strncpy (exp); - case BUILT_IN_OBJECT_SIZE: - return fold_builtin_object_size (arglist); - case BUILT_IN_MEMCPY_CHK: - case BUILT_IN_MEMPCPY_CHK: - case BUILT_IN_MEMMOVE_CHK: - case BUILT_IN_MEMSET_CHK: - return fold_builtin_memory_chk (fndecl, arglist, NULL_TREE, ignore, - DECL_FUNCTION_CODE (fndecl)); - case BUILT_IN_STRCPY_CHK: - case BUILT_IN_STPCPY_CHK: - return fold_builtin_stxcpy_chk (fndecl, arglist, NULL_TREE, ignore, - DECL_FUNCTION_CODE (fndecl)); - case BUILT_IN_STRNCPY_CHK: - return fold_builtin_strncpy_chk (arglist, NULL_TREE); - case BUILT_IN_STRCAT_CHK: - return fold_builtin_strcat_chk (fndecl, arglist); - case BUILT_IN_STRNCAT_CHK: - return fold_builtin_strncat_chk (fndecl, arglist); - case BUILT_IN_SPRINTF_CHK: - case BUILT_IN_VSPRINTF_CHK: - return fold_builtin_sprintf_chk (arglist, DECL_FUNCTION_CODE (fndecl)); - case BUILT_IN_SNPRINTF_CHK: - case BUILT_IN_VSNPRINTF_CHK: - return fold_builtin_snprintf_chk (arglist, NULL_TREE, - DECL_FUNCTION_CODE (fndecl)); + case BUILT_IN_MEMCMP: + return fold_builtin_memcmp (exp); - case BUILT_IN_PRINTF: - case BUILT_IN_PRINTF_UNLOCKED: - case BUILT_IN_VPRINTF: - case BUILT_IN_PRINTF_CHK: - case BUILT_IN_VPRINTF_CHK: - return fold_builtin_printf (fndecl, arglist, ignore, - DECL_FUNCTION_CODE (fndecl)); + case BUILT_IN_STRCMP: + return fold_builtin_strcmp (exp); - case BUILT_IN_FPRINTF: - case BUILT_IN_FPRINTF_UNLOCKED: - case BUILT_IN_VFPRINTF: - case BUILT_IN_FPRINTF_CHK: - case BUILT_IN_VFPRINTF_CHK: - return fold_builtin_fprintf (fndecl, arglist, ignore, - DECL_FUNCTION_CODE (fndecl)); + case BUILT_IN_STRNCMP: + return fold_builtin_strncmp (exp); default: break; @@ -9178,23 +6940,6 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) return 0; } -/* A wrapper function for builtin folding that prevents warnings for - "statement without effect" and the like, caused by removing the - call node earlier than the warning is generated. */ - -tree -fold_builtin (tree fndecl, tree arglist, bool ignore) -{ - tree exp = fold_builtin_1 (fndecl, arglist, ignore); - if (exp) - { - exp = build1 (NOP_EXPR, TREE_TYPE (exp), exp); - TREE_NO_WARNING (exp) = 1; - } - - return exp; -} - /* Conveniently construct a function call expression. */ tree @@ -9203,8 +6948,9 @@ build_function_call_expr (tree fn, tree arglist) tree call_expr; call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn); - return fold_build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), - call_expr, arglist, NULL_TREE); + call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), + call_expr, arglist); + return fold (call_expr); } /* This function validates the types of a function call argument list @@ -9239,14 +6985,8 @@ validate_arglist (tree arglist, ...) /* If no parameters remain or the parameter's code does not match the specified code, return false. Otherwise continue checking any remaining arguments. */ - if (arglist == 0) - goto end; - if (code == POINTER_TYPE) - { - if (! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))) - goto end; - } - else if (code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist)))) + if (arglist == 0 + || code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist)))) goto end; break; } @@ -9274,1927 +7014,41 @@ default_expand_builtin (tree exp ATTRIBUTE_UNUSED, return NULL_RTX; } -/* Returns true is EXP represents data that would potentially reside - in a readonly section. */ - -static bool -readonly_data_expr (tree exp) -{ - STRIP_NOPS (exp); - - if (TREE_CODE (exp) != ADDR_EXPR) - return false; - - exp = get_base_address (TREE_OPERAND (exp, 0)); - if (!exp) - return false; - - /* Make sure we call decl_readonly_section only for trees it - can handle (since it returns true for everything it doesn't - understand). */ - if (TREE_CODE (exp) == STRING_CST - || TREE_CODE (exp) == CONSTRUCTOR - || (TREE_CODE (exp) == VAR_DECL && TREE_STATIC (exp))) - return decl_readonly_section (exp, 0); - else - return false; -} - -/* Simplify a call to the strstr builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -fold_builtin_strstr (tree arglist, tree type) -{ - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return 0; - else - { - tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); - tree fn; - const char *p1, *p2; - - p2 = c_getstr (s2); - if (p2 == NULL) - return 0; - - p1 = c_getstr (s1); - if (p1 != NULL) - { - const char *r = strstr (p1, p2); - tree tem; - - if (r == NULL) - return build_int_cst (TREE_TYPE (s1), 0); - - /* Return an offset into the constant string argument. */ - tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1), - s1, build_int_cst (TREE_TYPE (s1), r - p1)); - return fold_convert (type, tem); - } - - /* The argument is const char *, and the result is char *, so we need - a type conversion here to avoid a warning. */ - if (p2[0] == '\0') - return fold_convert (type, s1); - - if (p2[1] != '\0') - return 0; - - fn = implicit_built_in_decls[BUILT_IN_STRCHR]; - if (!fn) - return 0; - - /* New argument list transforming strstr(s1, s2) to - strchr(s1, s2[0]). */ - arglist = build_tree_list (NULL_TREE, - build_int_cst (NULL_TREE, p2[0])); - arglist = tree_cons (NULL_TREE, s1, arglist); - return build_function_call_expr (fn, arglist); - } -} - -/* Simplify a call to the strchr builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -fold_builtin_strchr (tree arglist, tree type) -{ - if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return 0; - else - { - tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); - const char *p1; - - if (TREE_CODE (s2) != INTEGER_CST) - return 0; - - p1 = c_getstr (s1); - if (p1 != NULL) - { - char c; - const char *r; - tree tem; - - if (target_char_cast (s2, &c)) - return 0; - - r = strchr (p1, c); - - if (r == NULL) - return build_int_cst (TREE_TYPE (s1), 0); - - /* Return an offset into the constant string argument. */ - tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1), - s1, build_int_cst (TREE_TYPE (s1), r - p1)); - return fold_convert (type, tem); - } - return 0; - } -} - -/* Simplify a call to the strrchr builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -fold_builtin_strrchr (tree arglist, tree type) -{ - if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return 0; - else - { - tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); - tree fn; - const char *p1; - - if (TREE_CODE (s2) != INTEGER_CST) - return 0; - - p1 = c_getstr (s1); - if (p1 != NULL) - { - char c; - const char *r; - tree tem; - - if (target_char_cast (s2, &c)) - return 0; - - r = strrchr (p1, c); - - if (r == NULL) - return build_int_cst (TREE_TYPE (s1), 0); - - /* Return an offset into the constant string argument. */ - tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1), - s1, build_int_cst (TREE_TYPE (s1), r - p1)); - return fold_convert (type, tem); - } - - if (! integer_zerop (s2)) - return 0; - - fn = implicit_built_in_decls[BUILT_IN_STRCHR]; - if (!fn) - return 0; - - /* Transform strrchr(s1, '\0') to strchr(s1, '\0'). */ - return build_function_call_expr (fn, arglist); - } -} - -/* Simplify a call to the strpbrk builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -fold_builtin_strpbrk (tree arglist, tree type) -{ - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return 0; - else - { - tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); - tree fn; - const char *p1, *p2; - - p2 = c_getstr (s2); - if (p2 == NULL) - return 0; - - p1 = c_getstr (s1); - if (p1 != NULL) - { - const char *r = strpbrk (p1, p2); - tree tem; - - if (r == NULL) - return build_int_cst (TREE_TYPE (s1), 0); - - /* Return an offset into the constant string argument. */ - tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1), - s1, build_int_cst (TREE_TYPE (s1), r - p1)); - return fold_convert (type, tem); - } - - if (p2[0] == '\0') - /* strpbrk(x, "") == NULL. - Evaluate and ignore s1 in case it had side-effects. */ - return omit_one_operand (TREE_TYPE (s1), integer_zero_node, s1); - - if (p2[1] != '\0') - return 0; /* Really call strpbrk. */ - - fn = implicit_built_in_decls[BUILT_IN_STRCHR]; - if (!fn) - return 0; - - /* New argument list transforming strpbrk(s1, s2) to - strchr(s1, s2[0]). */ - arglist = build_tree_list (NULL_TREE, - build_int_cst (NULL_TREE, p2[0])); - arglist = tree_cons (NULL_TREE, s1, arglist); - return build_function_call_expr (fn, arglist); - } -} - -/* Simplify a call to the strcat builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -fold_builtin_strcat (tree arglist) -{ - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return 0; - else - { - tree dst = TREE_VALUE (arglist), - src = TREE_VALUE (TREE_CHAIN (arglist)); - const char *p = c_getstr (src); - - /* If the string length is zero, return the dst parameter. */ - if (p && *p == '\0') - return dst; - - return 0; - } -} - -/* Simplify a call to the strncat builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -fold_builtin_strncat (tree arglist) -{ - if (!validate_arglist (arglist, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return 0; - else - { - tree dst = TREE_VALUE (arglist); - tree src = TREE_VALUE (TREE_CHAIN (arglist)); - tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - const char *p = c_getstr (src); - - /* If the requested length is zero, or the src parameter string - length is zero, return the dst parameter. */ - if (integer_zerop (len) || (p && *p == '\0')) - return omit_two_operands (TREE_TYPE (dst), dst, src, len); - - /* If the requested len is greater than or equal to the string - length, call strcat. */ - if (TREE_CODE (len) == INTEGER_CST && p - && compare_tree_int (len, strlen (p)) >= 0) - { - tree newarglist - = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src)); - tree fn = implicit_built_in_decls[BUILT_IN_STRCAT]; - - /* If the replacement _DECL isn't initialized, don't do the - transformation. */ - if (!fn) - return 0; - - return build_function_call_expr (fn, newarglist); - } - return 0; - } -} - -/* Simplify a call to the strspn builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -fold_builtin_strspn (tree arglist) -{ - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return 0; - else - { - tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); - const char *p1 = c_getstr (s1), *p2 = c_getstr (s2); - - /* If both arguments are constants, evaluate at compile-time. */ - if (p1 && p2) - { - const size_t r = strspn (p1, p2); - return size_int (r); - } - - /* If either argument is "", return 0. */ - if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')) - /* Evaluate and ignore both arguments in case either one has - side-effects. */ - return omit_two_operands (integer_type_node, integer_zero_node, - s1, s2); - return 0; - } -} - -/* Simplify a call to the strcspn builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -fold_builtin_strcspn (tree arglist) -{ - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return 0; - else - { - tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); - const char *p1 = c_getstr (s1), *p2 = c_getstr (s2); - - /* If both arguments are constants, evaluate at compile-time. */ - if (p1 && p2) - { - const size_t r = strcspn (p1, p2); - return size_int (r); - } +/* Instantiate all remaining CONSTANT_P_RTX nodes. */ - /* If the first argument is "", return 0. */ - if (p1 && *p1 == '\0') - { - /* Evaluate and ignore argument s2 in case it has - side-effects. */ - return omit_one_operand (integer_type_node, - integer_zero_node, s2); - } - - /* If the second argument is "", return __builtin_strlen(s1). */ - if (p2 && *p2 == '\0') - { - tree newarglist = build_tree_list (NULL_TREE, s1), - fn = implicit_built_in_decls[BUILT_IN_STRLEN]; - - /* If the replacement _DECL isn't initialized, don't do the - transformation. */ - if (!fn) - return 0; - - return build_function_call_expr (fn, newarglist); - } - return 0; - } -} - -/* Fold a call to the fputs builtin. IGNORE is true if the value returned - by the builtin will be ignored. UNLOCKED is true is true if this - actually a call to fputs_unlocked. If LEN in non-NULL, it represents - the known length of the string. Return NULL_TREE if no simplification - was possible. */ - -tree -fold_builtin_fputs (tree arglist, bool ignore, bool unlocked, tree len) +void +purge_builtin_constant_p (void) { - tree fn; - /* If we're using an unlocked function, assume the other unlocked - functions exist explicitly. */ - tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED] - : implicit_built_in_decls[BUILT_IN_FPUTC]; - tree const fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED] - : implicit_built_in_decls[BUILT_IN_FWRITE]; + rtx insn, set, arg, new, note; - /* If the return value is used, don't do the transformation. */ - if (!ignore) - return 0; - - /* Verify the arguments in the original call. */ - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return 0; - - if (! len) - len = c_strlen (TREE_VALUE (arglist), 0); - - /* Get the length of the string passed to fputs. If the length - can't be determined, punt. */ - if (!len - || TREE_CODE (len) != INTEGER_CST) - return 0; - - switch (compare_tree_int (len, 1)) - { - case -1: /* length is 0, delete the call entirely . */ - return omit_one_operand (integer_type_node, integer_zero_node, - TREE_VALUE (TREE_CHAIN (arglist))); - - case 0: /* length is 1, call fputc. */ - { - const char *p = c_getstr (TREE_VALUE (arglist)); - - if (p != NULL) - { - /* New argument list transforming fputs(string, stream) to - fputc(string[0], stream). */ - arglist = build_tree_list (NULL_TREE, - TREE_VALUE (TREE_CHAIN (arglist))); - arglist = tree_cons (NULL_TREE, - build_int_cst (NULL_TREE, p[0]), - arglist); - fn = fn_fputc; - break; - } - } - /* FALLTHROUGH */ - case 1: /* length is greater than 1, call fwrite. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (INSN_P (insn) + && (set = single_set (insn)) != NULL_RTX + && (GET_CODE (arg = SET_SRC (set)) == CONSTANT_P_RTX + || (GET_CODE (arg) == SUBREG + && (GET_CODE (arg = SUBREG_REG (arg)) + == CONSTANT_P_RTX)))) { - tree string_arg; - - /* If optimizing for size keep fputs. */ - if (optimize_size) - return 0; - string_arg = TREE_VALUE (arglist); - /* New argument list transforming fputs(string, stream) to - fwrite(string, 1, len, stream). */ - arglist = build_tree_list (NULL_TREE, - TREE_VALUE (TREE_CHAIN (arglist))); - arglist = tree_cons (NULL_TREE, len, arglist); - arglist = tree_cons (NULL_TREE, size_one_node, arglist); - arglist = tree_cons (NULL_TREE, string_arg, arglist); - fn = fn_fwrite; - break; - } - default: - gcc_unreachable (); - } - - /* If the replacement _DECL isn't initialized, don't do the - transformation. */ - if (!fn) - return 0; - - /* These optimizations are only performed when the result is ignored, - hence there's no need to cast the result to integer_type_node. */ - return build_function_call_expr (fn, arglist); -} - -/* Fold the new_arg's arguments (ARGLIST). Returns true if there was an error - produced. False otherwise. This is done so that we don't output the error - or warning twice or three times. */ -bool -fold_builtin_next_arg (tree arglist) -{ - tree fntype = TREE_TYPE (current_function_decl); - - if (TYPE_ARG_TYPES (fntype) == 0 - || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) - == void_type_node)) - { - error ("%<va_start%> used in function with fixed args"); - return true; - } - else if (!arglist) - { - /* Evidently an out of date version of <stdarg.h>; can't validate - va_start's second argument, but can still work as intended. */ - warning (0, "%<__builtin_next_arg%> called without an argument"); - return true; - } - /* We use __builtin_va_start (ap, 0, 0) or __builtin_next_arg (0, 0) - when we checked the arguments and if needed issued a warning. */ - else if (!TREE_CHAIN (arglist) - || !integer_zerop (TREE_VALUE (arglist)) - || !integer_zerop (TREE_VALUE (TREE_CHAIN (arglist))) - || TREE_CHAIN (TREE_CHAIN (arglist))) - { - tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl)); - tree arg = TREE_VALUE (arglist); - - if (TREE_CHAIN (arglist)) - { - error ("%<va_start%> used with too many arguments"); - return true; - } - - /* Strip off all nops for the sake of the comparison. This - is not quite the same as STRIP_NOPS. It does more. - We must also strip off INDIRECT_EXPR for C++ reference - parameters. */ - while (TREE_CODE (arg) == NOP_EXPR - || TREE_CODE (arg) == CONVERT_EXPR - || TREE_CODE (arg) == NON_LVALUE_EXPR - || TREE_CODE (arg) == INDIRECT_REF) - arg = TREE_OPERAND (arg, 0); - if (arg != last_parm) - { - /* FIXME: Sometimes with the tree optimizers we can get the - not the last argument even though the user used the last - argument. We just warn and set the arg to be the last - argument so that we will get wrong-code because of - it. */ - warning (0, "second parameter of %<va_start%> not last named argument"); - } - /* We want to verify the second parameter just once before the tree - optimizers are run and then avoid keeping it in the tree, - as otherwise we could warn even for correct code like: - void foo (int i, ...) - { va_list ap; i++; va_start (ap, i); va_end (ap); } */ - TREE_VALUE (arglist) = integer_zero_node; - TREE_CHAIN (arglist) = build_tree_list (NULL, integer_zero_node); - } - return false; -} - - -/* Simplify a call to the sprintf builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. If IGNORED is true, it means that - the caller does not use the returned value of the function. */ - -static tree -fold_builtin_sprintf (tree arglist, int ignored) -{ - tree call, retval, dest, fmt; - const char *fmt_str = NULL; - - /* Verify the required arguments in the original call. We deal with two - types of sprintf() calls: 'sprintf (str, fmt)' and - 'sprintf (dest, "%s", orig)'. */ - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE) - && !validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, POINTER_TYPE, - VOID_TYPE)) - return NULL_TREE; - - /* Get the destination string and the format specifier. */ - dest = TREE_VALUE (arglist); - fmt = TREE_VALUE (TREE_CHAIN (arglist)); - arglist = TREE_CHAIN (TREE_CHAIN (arglist)); - - /* Check whether the format is a literal string constant. */ - fmt_str = c_getstr (fmt); - if (fmt_str == NULL) - return NULL_TREE; - - call = NULL_TREE; - retval = NULL_TREE; - - if (!init_target_chars()) - return 0; - - /* If the format doesn't contain % args or %%, use strcpy. */ - if (strchr (fmt_str, target_percent) == NULL) - { - tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; - - if (!fn) - return NULL_TREE; - - /* Don't optimize sprintf (buf, "abc", ptr++). */ - if (arglist) - return NULL_TREE; - - /* Convert sprintf (str, fmt) into strcpy (str, fmt) when - 'format' is known to contain no % formats. */ - arglist = build_tree_list (NULL_TREE, fmt); - arglist = tree_cons (NULL_TREE, dest, arglist); - call = build_function_call_expr (fn, arglist); - if (!ignored) - retval = build_int_cst (NULL_TREE, strlen (fmt_str)); - } - - /* If the format is "%s", use strcpy if the result isn't used. */ - else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0) - { - tree fn, orig; - fn = implicit_built_in_decls[BUILT_IN_STRCPY]; - - if (!fn) - return NULL_TREE; - - /* Don't crash on sprintf (str1, "%s"). */ - if (!arglist) - return NULL_TREE; - - /* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2). */ - orig = TREE_VALUE (arglist); - arglist = build_tree_list (NULL_TREE, orig); - arglist = tree_cons (NULL_TREE, dest, arglist); - if (!ignored) - { - retval = c_strlen (orig, 1); - if (!retval || TREE_CODE (retval) != INTEGER_CST) - return NULL_TREE; - } - call = build_function_call_expr (fn, arglist); - } - - if (call && retval) - { - retval = fold_convert - (TREE_TYPE (TREE_TYPE (implicit_built_in_decls[BUILT_IN_SPRINTF])), - retval); - return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval); - } - else - return call; -} - -/* Expand a call to __builtin_object_size. */ - -rtx -expand_builtin_object_size (tree exp) -{ - tree ost; - int object_size_type; - tree fndecl = get_callee_fndecl (exp); - tree arglist = TREE_OPERAND (exp, 1); - location_t locus = EXPR_LOCATION (exp); - - if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - { - error ("%Hfirst argument of %D must be a pointer, second integer constant", - &locus, fndecl); - expand_builtin_trap (); - return const0_rtx; - } - - ost = TREE_VALUE (TREE_CHAIN (arglist)); - STRIP_NOPS (ost); - - if (TREE_CODE (ost) != INTEGER_CST - || tree_int_cst_sgn (ost) < 0 - || compare_tree_int (ost, 3) > 0) - { - error ("%Hlast argument of %D is not integer constant between 0 and 3", - &locus, fndecl); - expand_builtin_trap (); - return const0_rtx; - } - - object_size_type = tree_low_cst (ost, 0); - - return object_size_type < 2 ? constm1_rtx : const0_rtx; -} - -/* Expand EXP, a call to the __mem{cpy,pcpy,move,set}_chk builtin. - FCODE is the BUILT_IN_* to use. - Return 0 if we failed; the caller should emit a normal call, - otherwise try to get the result in TARGET, if convenient (and in - mode MODE if that's convenient). */ - -static rtx -expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode, - enum built_in_function fcode) -{ - tree arglist = TREE_OPERAND (exp, 1); - tree dest, src, len, size; - - if (!validate_arglist (arglist, - POINTER_TYPE, - fcode == BUILT_IN_MEMSET_CHK - ? INTEGER_TYPE : POINTER_TYPE, - INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return 0; - - dest = TREE_VALUE (arglist); - src = TREE_VALUE (TREE_CHAIN (arglist)); - len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist)))); - - if (! host_integerp (size, 1)) - return 0; - - if (host_integerp (len, 1) || integer_all_onesp (size)) - { - tree fn; - - if (! integer_all_onesp (size) && tree_int_cst_lt (size, len)) - { - location_t locus = EXPR_LOCATION (exp); - warning (0, "%Hcall to %D will always overflow destination buffer", - &locus, get_callee_fndecl (exp)); - return 0; - } - - arglist = build_tree_list (NULL_TREE, len); - arglist = tree_cons (NULL_TREE, src, arglist); - arglist = tree_cons (NULL_TREE, dest, arglist); - - fn = NULL_TREE; - /* If __builtin_mem{cpy,pcpy,move,set}_chk is used, assume - mem{cpy,pcpy,move,set} is available. */ - switch (fcode) - { - case BUILT_IN_MEMCPY_CHK: - fn = built_in_decls[BUILT_IN_MEMCPY]; - break; - case BUILT_IN_MEMPCPY_CHK: - fn = built_in_decls[BUILT_IN_MEMPCPY]; - break; - case BUILT_IN_MEMMOVE_CHK: - fn = built_in_decls[BUILT_IN_MEMMOVE]; - break; - case BUILT_IN_MEMSET_CHK: - fn = built_in_decls[BUILT_IN_MEMSET]; - break; - default: - break; - } - - if (! fn) - return 0; + arg = XEXP (arg, 0); + new = CONSTANT_P (arg) ? const1_rtx : const0_rtx; + validate_change (insn, &SET_SRC (set), new, 0); - fn = build_function_call_expr (fn, arglist); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); - return expand_expr (fn, target, mode, EXPAND_NORMAL); - } - else if (fcode == BUILT_IN_MEMSET_CHK) - return 0; - else - { - unsigned int dest_align - = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); - - /* If DEST is not a pointer type, call the normal function. */ - if (dest_align == 0) - return 0; - - /* If SRC and DEST are the same (and not volatile), do nothing. */ - if (operand_equal_p (src, dest, 0)) - { - tree expr; - - if (fcode != BUILT_IN_MEMPCPY_CHK) - { - /* Evaluate and ignore LEN in case it has side-effects. */ - expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL); - return expand_expr (dest, target, mode, EXPAND_NORMAL); - } - - len = fold_convert (TREE_TYPE (dest), len); - expr = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len); - return expand_expr (expr, target, mode, EXPAND_NORMAL); - } - - /* __memmove_chk special case. */ - if (fcode == BUILT_IN_MEMMOVE_CHK) - { - unsigned int src_align - = get_pointer_alignment (src, BIGGEST_ALIGNMENT); - - if (src_align == 0) - return 0; - - /* If src is categorized for a readonly section we can use - normal __memcpy_chk. */ - if (readonly_data_expr (src)) - { - tree fn = built_in_decls[BUILT_IN_MEMCPY_CHK]; - if (!fn) - return 0; - fn = build_function_call_expr (fn, arglist); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); - return expand_expr (fn, target, mode, EXPAND_NORMAL); - } - } - return 0; - } -} - -/* Emit warning if a buffer overflow is detected at compile time. */ - -static void -maybe_emit_chk_warning (tree exp, enum built_in_function fcode) -{ - int arg_mask, is_strlen = 0; - tree arglist = TREE_OPERAND (exp, 1), a; - tree len, size; - location_t locus; - - switch (fcode) - { - case BUILT_IN_STRCPY_CHK: - case BUILT_IN_STPCPY_CHK: - /* For __strcat_chk the warning will be emitted only if overflowing - by at least strlen (dest) + 1 bytes. */ - case BUILT_IN_STRCAT_CHK: - arg_mask = 6; - is_strlen = 1; - break; - case BUILT_IN_STRNCPY_CHK: - arg_mask = 12; - break; - case BUILT_IN_SNPRINTF_CHK: - case BUILT_IN_VSNPRINTF_CHK: - arg_mask = 10; - break; - default: - gcc_unreachable (); - } - - len = NULL_TREE; - size = NULL_TREE; - for (a = arglist; a && arg_mask; a = TREE_CHAIN (a), arg_mask >>= 1) - if (arg_mask & 1) - { - if (len) - size = a; - else - len = a; + /* Remove the REG_EQUAL note from the insn. */ + if ((note = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0) + remove_note (insn, note); } - - if (!len || !size) - return; - - len = TREE_VALUE (len); - size = TREE_VALUE (size); - - if (! host_integerp (size, 1) || integer_all_onesp (size)) - return; - - if (is_strlen) - { - len = c_strlen (len, 1); - if (! len || ! host_integerp (len, 1) || tree_int_cst_lt (len, size)) - return; - } - else if (! host_integerp (len, 1) || ! tree_int_cst_lt (size, len)) - return; - - locus = EXPR_LOCATION (exp); - warning (0, "%Hcall to %D will always overflow destination buffer", - &locus, get_callee_fndecl (exp)); -} - -/* Emit warning if a buffer overflow is detected at compile time - in __sprintf_chk/__vsprintf_chk calls. */ - -static void -maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode) -{ - tree arglist = TREE_OPERAND (exp, 1); - tree dest, size, len, fmt, flag; - const char *fmt_str; - - /* Verify the required arguments in the original call. */ - if (! arglist) - return; - dest = TREE_VALUE (arglist); - arglist = TREE_CHAIN (arglist); - if (! arglist) - return; - flag = TREE_VALUE (arglist); - arglist = TREE_CHAIN (arglist); - if (! arglist) - return; - size = TREE_VALUE (arglist); - arglist = TREE_CHAIN (arglist); - if (! arglist) - return; - fmt = TREE_VALUE (arglist); - arglist = TREE_CHAIN (arglist); - - if (! host_integerp (size, 1) || integer_all_onesp (size)) - return; - - /* Check whether the format is a literal string constant. */ - fmt_str = c_getstr (fmt); - if (fmt_str == NULL) - return; - - if (!init_target_chars()) - return; - - /* If the format doesn't contain % args or %%, we know its size. */ - if (strchr (fmt_str, target_percent) == 0) - len = build_int_cstu (size_type_node, strlen (fmt_str)); - /* If the format is "%s" and first ... argument is a string literal, - we know it too. */ - else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0) - { - tree arg; - - if (! arglist) - return; - arg = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (arg))) - return; - - len = c_strlen (arg, 1); - if (!len || ! host_integerp (len, 1)) - return; - } - else - return; - - if (! tree_int_cst_lt (len, size)) - { - location_t locus = EXPR_LOCATION (exp); - warning (0, "%Hcall to %D will always overflow destination buffer", - &locus, get_callee_fndecl (exp)); - } -} - -/* Fold a call to __builtin_object_size, if possible. */ - -tree -fold_builtin_object_size (tree arglist) -{ - tree ptr, ost, ret = 0; - int object_size_type; - - if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return 0; - - ptr = TREE_VALUE (arglist); - ost = TREE_VALUE (TREE_CHAIN (arglist)); - STRIP_NOPS (ost); - - if (TREE_CODE (ost) != INTEGER_CST - || tree_int_cst_sgn (ost) < 0 - || compare_tree_int (ost, 3) > 0) - return 0; - - object_size_type = tree_low_cst (ost, 0); - - /* __builtin_object_size doesn't evaluate side-effects in its arguments; - if there are any side-effects, it returns (size_t) -1 for types 0 and 1 - and (size_t) 0 for types 2 and 3. */ - if (TREE_SIDE_EFFECTS (ptr)) - return fold_convert (size_type_node, - object_size_type < 2 - ? integer_minus_one_node : integer_zero_node); - - if (TREE_CODE (ptr) == ADDR_EXPR) - ret = build_int_cstu (size_type_node, - compute_builtin_object_size (ptr, object_size_type)); - - else if (TREE_CODE (ptr) == SSA_NAME) - { - unsigned HOST_WIDE_INT bytes; - - /* If object size is not known yet, delay folding until - later. Maybe subsequent passes will help determining - it. */ - bytes = compute_builtin_object_size (ptr, object_size_type); - if (bytes != (unsigned HOST_WIDE_INT) (object_size_type < 2 - ? -1 : 0)) - ret = build_int_cstu (size_type_node, bytes); - } - - if (ret) - { - ret = force_fit_type (ret, -1, false, false); - if (TREE_CONSTANT_OVERFLOW (ret)) - ret = 0; - } - - return ret; -} - -/* Fold a call to the __mem{cpy,pcpy,move,set}_chk builtin. - IGNORE is true, if return value can be ignored. FCODE is the BUILT_IN_* - code of the builtin. If MAXLEN is not NULL, it is maximum length - passed as third argument. */ - -tree -fold_builtin_memory_chk (tree fndecl, tree arglist, tree maxlen, bool ignore, - enum built_in_function fcode) -{ - tree dest, src, len, size, fn; - - if (!validate_arglist (arglist, - POINTER_TYPE, - fcode == BUILT_IN_MEMSET_CHK - ? INTEGER_TYPE : POINTER_TYPE, - INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return 0; - - dest = TREE_VALUE (arglist); - /* Actually val for __memset_chk, but it doesn't matter. */ - src = TREE_VALUE (TREE_CHAIN (arglist)); - len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist)))); - - /* If SRC and DEST are the same (and not volatile), return DEST - (resp. DEST+LEN for __mempcpy_chk). */ - if (fcode != BUILT_IN_MEMSET_CHK && operand_equal_p (src, dest, 0)) - { - if (fcode != BUILT_IN_MEMPCPY_CHK) - return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, len); - else - { - tree temp = fold_convert (TREE_TYPE (dest), len); - temp = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, temp); - return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), temp); - } - } - - if (! host_integerp (size, 1)) - return 0; - - if (! integer_all_onesp (size)) - { - if (! host_integerp (len, 1)) - { - /* If LEN is not constant, try MAXLEN too. - For MAXLEN only allow optimizing into non-_ocs function - if SIZE is >= MAXLEN, never convert to __ocs_fail (). */ - if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1)) - { - if (fcode == BUILT_IN_MEMPCPY_CHK && ignore) - { - /* (void) __mempcpy_chk () can be optimized into - (void) __memcpy_chk (). */ - fn = built_in_decls[BUILT_IN_MEMCPY_CHK]; - if (!fn) - return 0; - - return build_function_call_expr (fn, arglist); - } - return 0; - } - } - else - maxlen = len; - - if (tree_int_cst_lt (size, maxlen)) - return 0; - } - - arglist = build_tree_list (NULL_TREE, len); - arglist = tree_cons (NULL_TREE, src, arglist); - arglist = tree_cons (NULL_TREE, dest, arglist); - - fn = NULL_TREE; - /* If __builtin_mem{cpy,pcpy,move,set}_chk is used, assume - mem{cpy,pcpy,move,set} is available. */ - switch (fcode) - { - case BUILT_IN_MEMCPY_CHK: - fn = built_in_decls[BUILT_IN_MEMCPY]; - break; - case BUILT_IN_MEMPCPY_CHK: - fn = built_in_decls[BUILT_IN_MEMPCPY]; - break; - case BUILT_IN_MEMMOVE_CHK: - fn = built_in_decls[BUILT_IN_MEMMOVE]; - break; - case BUILT_IN_MEMSET_CHK: - fn = built_in_decls[BUILT_IN_MEMSET]; - break; - default: - break; - } - - if (!fn) - return 0; - - return build_function_call_expr (fn, arglist); -} - -/* Fold a call to the __st[rp]cpy_chk builtin. - IGNORE is true, if return value can be ignored. FCODE is the BUILT_IN_* - code of the builtin. If MAXLEN is not NULL, it is maximum length of - strings passed as second argument. */ - -tree -fold_builtin_stxcpy_chk (tree fndecl, tree arglist, tree maxlen, bool ignore, - enum built_in_function fcode) -{ - tree dest, src, size, len, fn; - - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, - VOID_TYPE)) - return 0; - - dest = TREE_VALUE (arglist); - src = TREE_VALUE (TREE_CHAIN (arglist)); - size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - - /* If SRC and DEST are the same (and not volatile), return DEST. */ - if (fcode == BUILT_IN_STRCPY_CHK && operand_equal_p (src, dest, 0)) - return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), dest); - - if (! host_integerp (size, 1)) - return 0; - - if (! integer_all_onesp (size)) - { - len = c_strlen (src, 1); - if (! len || ! host_integerp (len, 1)) - { - /* If LEN is not constant, try MAXLEN too. - For MAXLEN only allow optimizing into non-_ocs function - if SIZE is >= MAXLEN, never convert to __ocs_fail (). */ - if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1)) - { - if (fcode == BUILT_IN_STPCPY_CHK) - { - if (! ignore) - return 0; - - /* If return value of __stpcpy_chk is ignored, - optimize into __strcpy_chk. */ - fn = built_in_decls[BUILT_IN_STRCPY_CHK]; - if (!fn) - return 0; - - return build_function_call_expr (fn, arglist); - } - - if (! len || TREE_SIDE_EFFECTS (len)) - return 0; - - /* If c_strlen returned something, but not a constant, - transform __strcpy_chk into __memcpy_chk. */ - fn = built_in_decls[BUILT_IN_MEMCPY_CHK]; - if (!fn) - return 0; - - len = size_binop (PLUS_EXPR, len, ssize_int (1)); - arglist = build_tree_list (NULL_TREE, size); - arglist = tree_cons (NULL_TREE, len, arglist); - arglist = tree_cons (NULL_TREE, src, arglist); - arglist = tree_cons (NULL_TREE, dest, arglist); - return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), - build_function_call_expr (fn, arglist)); - } - } - else - maxlen = len; - - if (! tree_int_cst_lt (maxlen, size)) - return 0; - } - - arglist = build_tree_list (NULL_TREE, src); - arglist = tree_cons (NULL_TREE, dest, arglist); - - /* If __builtin_st{r,p}cpy_chk is used, assume st{r,p}cpy is available. */ - fn = built_in_decls[fcode == BUILT_IN_STPCPY_CHK - ? BUILT_IN_STPCPY : BUILT_IN_STRCPY]; - if (!fn) - return 0; - - return build_function_call_expr (fn, arglist); -} - -/* Fold a call to the __strncpy_chk builtin. - If MAXLEN is not NULL, it is maximum length passed as third argument. */ - -tree -fold_builtin_strncpy_chk (tree arglist, tree maxlen) -{ - tree dest, src, size, len, fn; - - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, - INTEGER_TYPE, VOID_TYPE)) - return 0; - - dest = TREE_VALUE (arglist); - src = TREE_VALUE (TREE_CHAIN (arglist)); - len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist)))); - - if (! host_integerp (size, 1)) - return 0; - - if (! integer_all_onesp (size)) - { - if (! host_integerp (len, 1)) - { - /* If LEN is not constant, try MAXLEN too. - For MAXLEN only allow optimizing into non-_ocs function - if SIZE is >= MAXLEN, never convert to __ocs_fail (). */ - if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1)) - return 0; - } - else - maxlen = len; - - if (tree_int_cst_lt (size, maxlen)) - return 0; - } - - arglist = build_tree_list (NULL_TREE, len); - arglist = tree_cons (NULL_TREE, src, arglist); - arglist = tree_cons (NULL_TREE, dest, arglist); - - /* If __builtin_strncpy_chk is used, assume strncpy is available. */ - fn = built_in_decls[BUILT_IN_STRNCPY]; - if (!fn) - return 0; - - return build_function_call_expr (fn, arglist); -} - -/* Fold a call to the __strcat_chk builtin FNDECL with ARGLIST. */ - -static tree -fold_builtin_strcat_chk (tree fndecl, tree arglist) -{ - tree dest, src, size, fn; - const char *p; - - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, - VOID_TYPE)) - return 0; - - dest = TREE_VALUE (arglist); - src = TREE_VALUE (TREE_CHAIN (arglist)); - size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - - p = c_getstr (src); - /* If the SRC parameter is "", return DEST. */ - if (p && *p == '\0') - return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src); - - if (! host_integerp (size, 1) || ! integer_all_onesp (size)) - return 0; - - arglist = build_tree_list (NULL_TREE, src); - arglist = tree_cons (NULL_TREE, dest, arglist); - - /* If __builtin_strcat_chk is used, assume strcat is available. */ - fn = built_in_decls[BUILT_IN_STRCAT]; - if (!fn) - return 0; - - return build_function_call_expr (fn, arglist); -} - -/* Fold a call to the __strncat_chk builtin EXP. */ - -static tree -fold_builtin_strncat_chk (tree fndecl, tree arglist) -{ - tree dest, src, size, len, fn; - const char *p; - - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, - INTEGER_TYPE, VOID_TYPE)) - return 0; - - dest = TREE_VALUE (arglist); - src = TREE_VALUE (TREE_CHAIN (arglist)); - len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist)))); - - p = c_getstr (src); - /* If the SRC parameter is "" or if LEN is 0, return DEST. */ - if (p && *p == '\0') - return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, len); - else if (integer_zerop (len)) - return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src); - - if (! host_integerp (size, 1)) - return 0; - - if (! integer_all_onesp (size)) - { - tree src_len = c_strlen (src, 1); - if (src_len - && host_integerp (src_len, 1) - && host_integerp (len, 1) - && ! tree_int_cst_lt (len, src_len)) - { - /* If LEN >= strlen (SRC), optimize into __strcat_chk. */ - fn = built_in_decls[BUILT_IN_STRCAT_CHK]; - if (!fn) - return 0; - - arglist = build_tree_list (NULL_TREE, size); - arglist = tree_cons (NULL_TREE, src, arglist); - arglist = tree_cons (NULL_TREE, dest, arglist); - return build_function_call_expr (fn, arglist); - } - return 0; - } - - arglist = build_tree_list (NULL_TREE, len); - arglist = tree_cons (NULL_TREE, src, arglist); - arglist = tree_cons (NULL_TREE, dest, arglist); - - /* If __builtin_strncat_chk is used, assume strncat is available. */ - fn = built_in_decls[BUILT_IN_STRNCAT]; - if (!fn) - return 0; - - return build_function_call_expr (fn, arglist); -} - -/* Fold a call to __{,v}sprintf_chk with argument list ARGLIST. Return 0 if - a normal call should be emitted rather than expanding the function - inline. FCODE is either BUILT_IN_SPRINTF_CHK or BUILT_IN_VSPRINTF_CHK. */ - -static tree -fold_builtin_sprintf_chk (tree arglist, enum built_in_function fcode) -{ - tree dest, size, len, fn, fmt, flag; - const char *fmt_str; - - /* Verify the required arguments in the original call. */ - if (! arglist) - return 0; - dest = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (dest))) - return 0; - arglist = TREE_CHAIN (arglist); - if (! arglist) - return 0; - flag = TREE_VALUE (arglist); - if (TREE_CODE (TREE_TYPE (flag)) != INTEGER_TYPE) - return 0; - arglist = TREE_CHAIN (arglist); - if (! arglist) - return 0; - size = TREE_VALUE (arglist); - if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE) - return 0; - arglist = TREE_CHAIN (arglist); - if (! arglist) - return 0; - fmt = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (fmt))) - return 0; - arglist = TREE_CHAIN (arglist); - - if (! host_integerp (size, 1)) - return 0; - - len = NULL_TREE; - - if (!init_target_chars()) - return 0; - - /* Check whether the format is a literal string constant. */ - fmt_str = c_getstr (fmt); - if (fmt_str != NULL) - { - /* If the format doesn't contain % args or %%, we know the size. */ - if (strchr (fmt_str, target_percent) == 0) - { - if (fcode != BUILT_IN_SPRINTF_CHK || arglist == NULL_TREE) - len = build_int_cstu (size_type_node, strlen (fmt_str)); - } - /* If the format is "%s" and first ... argument is a string literal, - we know the size too. */ - else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0) - { - tree arg; - - if (arglist && !TREE_CHAIN (arglist)) - { - arg = TREE_VALUE (arglist); - if (POINTER_TYPE_P (TREE_TYPE (arg))) - { - len = c_strlen (arg, 1); - if (! len || ! host_integerp (len, 1)) - len = NULL_TREE; - } - } - } - } - - if (! integer_all_onesp (size)) - { - if (! len || ! tree_int_cst_lt (len, size)) - return 0; - } - - /* Only convert __{,v}sprintf_chk to {,v}sprintf if flag is 0 - or if format doesn't contain % chars or is "%s". */ - if (! integer_zerop (flag)) - { - if (fmt_str == NULL) - return 0; - if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s)) - return 0; - } - - arglist = tree_cons (NULL_TREE, fmt, arglist); - arglist = tree_cons (NULL_TREE, dest, arglist); - - /* If __builtin_{,v}sprintf_chk is used, assume {,v}sprintf is available. */ - fn = built_in_decls[fcode == BUILT_IN_VSPRINTF_CHK - ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF]; - if (!fn) - return 0; - - return build_function_call_expr (fn, arglist); -} - -/* Fold a call to {,v}snprintf with argument list ARGLIST. Return 0 if - a normal call should be emitted rather than expanding the function - inline. FCODE is either BUILT_IN_SNPRINTF_CHK or - BUILT_IN_VSNPRINTF_CHK. If MAXLEN is not NULL, it is maximum length - passed as second argument. */ - -tree -fold_builtin_snprintf_chk (tree arglist, tree maxlen, - enum built_in_function fcode) -{ - tree dest, size, len, fn, fmt, flag; - const char *fmt_str; - - /* Verify the required arguments in the original call. */ - if (! arglist) - return 0; - dest = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (dest))) - return 0; - arglist = TREE_CHAIN (arglist); - if (! arglist) - return 0; - len = TREE_VALUE (arglist); - if (TREE_CODE (TREE_TYPE (len)) != INTEGER_TYPE) - return 0; - arglist = TREE_CHAIN (arglist); - if (! arglist) - return 0; - flag = TREE_VALUE (arglist); - if (TREE_CODE (TREE_TYPE (len)) != INTEGER_TYPE) - return 0; - arglist = TREE_CHAIN (arglist); - if (! arglist) - return 0; - size = TREE_VALUE (arglist); - if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE) - return 0; - arglist = TREE_CHAIN (arglist); - if (! arglist) - return 0; - fmt = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (fmt))) - return 0; - arglist = TREE_CHAIN (arglist); - - if (! host_integerp (size, 1)) - return 0; - - if (! integer_all_onesp (size)) - { - if (! host_integerp (len, 1)) - { - /* If LEN is not constant, try MAXLEN too. - For MAXLEN only allow optimizing into non-_ocs function - if SIZE is >= MAXLEN, never convert to __ocs_fail (). */ - if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1)) - return 0; - } - else - maxlen = len; - - if (tree_int_cst_lt (size, maxlen)) - return 0; - } - - if (!init_target_chars()) - return 0; - - /* Only convert __{,v}snprintf_chk to {,v}snprintf if flag is 0 - or if format doesn't contain % chars or is "%s". */ - if (! integer_zerop (flag)) - { - fmt_str = c_getstr (fmt); - if (fmt_str == NULL) - return 0; - if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s)) - return 0; - } - - arglist = tree_cons (NULL_TREE, fmt, arglist); - arglist = tree_cons (NULL_TREE, len, arglist); - arglist = tree_cons (NULL_TREE, dest, arglist); - - /* If __builtin_{,v}snprintf_chk is used, assume {,v}snprintf is - available. */ - fn = built_in_decls[fcode == BUILT_IN_VSNPRINTF_CHK - ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF]; - if (!fn) - return 0; - - return build_function_call_expr (fn, arglist); -} - -/* Fold a call to the {,v}printf{,_unlocked} and __{,v}printf_chk builtins. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. FCODE is the BUILT_IN_* - code of the function to be simplified. */ - -static tree -fold_builtin_printf (tree fndecl, tree arglist, bool ignore, - enum built_in_function fcode) -{ - tree fmt, fn = NULL_TREE, fn_putchar, fn_puts, arg, call; - const char *fmt_str = NULL; - - /* If the return value is used, don't do the transformation. */ - if (! ignore) - return 0; - - /* Verify the required arguments in the original call. */ - if (fcode == BUILT_IN_PRINTF_CHK || fcode == BUILT_IN_VPRINTF_CHK) - { - tree flag; - - if (! arglist) - return 0; - flag = TREE_VALUE (arglist); - if (TREE_CODE (TREE_TYPE (flag)) != INTEGER_TYPE - || TREE_SIDE_EFFECTS (flag)) - return 0; - arglist = TREE_CHAIN (arglist); - } - - if (! arglist) - return 0; - fmt = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (fmt))) - return 0; - arglist = TREE_CHAIN (arglist); - - /* Check whether the format is a literal string constant. */ - fmt_str = c_getstr (fmt); - if (fmt_str == NULL) - return NULL_TREE; - - if (fcode == BUILT_IN_PRINTF_UNLOCKED) - { - /* If we're using an unlocked function, assume the other - unlocked functions exist explicitly. */ - fn_putchar = built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]; - fn_puts = built_in_decls[BUILT_IN_PUTS_UNLOCKED]; - } - else - { - fn_putchar = implicit_built_in_decls[BUILT_IN_PUTCHAR]; - fn_puts = implicit_built_in_decls[BUILT_IN_PUTS]; - } - - if (!init_target_chars()) - return 0; - - if (strcmp (fmt_str, target_percent_s) == 0 || strchr (fmt_str, target_percent) == NULL) - { - const char *str; - - if (strcmp (fmt_str, target_percent_s) == 0) - { - if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK) - return 0; - - if (! arglist - || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))) - || TREE_CHAIN (arglist)) - return 0; - - str = c_getstr (TREE_VALUE (arglist)); - if (str == NULL) - return 0; - } - else - { - /* The format specifier doesn't contain any '%' characters. */ - if (fcode != BUILT_IN_VPRINTF && fcode != BUILT_IN_VPRINTF_CHK - && arglist) - return 0; - str = fmt_str; - } - - /* If the string was "", printf does nothing. */ - if (str[0] == '\0') - return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0); - - /* If the string has length of 1, call putchar. */ - if (str[1] == '\0') - { - /* Given printf("c"), (where c is any one character,) - convert "c"[0] to an int and pass that to the replacement - function. */ - arg = build_int_cst (NULL_TREE, str[0]); - arglist = build_tree_list (NULL_TREE, arg); - fn = fn_putchar; - } - else - { - /* If the string was "string\n", call puts("string"). */ - size_t len = strlen (str); - if ((unsigned char)str[len - 1] == target_newline) - { - /* Create a NUL-terminated string that's one char shorter - than the original, stripping off the trailing '\n'. */ - char *newstr = alloca (len); - memcpy (newstr, str, len - 1); - newstr[len - 1] = 0; - - arg = build_string_literal (len, newstr); - arglist = build_tree_list (NULL_TREE, arg); - fn = fn_puts; - } - else - /* We'd like to arrange to call fputs(string,stdout) here, - but we need stdout and don't have a way to get it yet. */ - return 0; - } - } - - /* The other optimizations can be done only on the non-va_list variants. */ - else if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK) - return 0; - - /* If the format specifier was "%s\n", call __builtin_puts(arg). */ - else if (strcmp (fmt_str, target_percent_s_newline) == 0) - { - if (! arglist - || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))) - || TREE_CHAIN (arglist)) - return 0; - fn = fn_puts; - } - - /* If the format specifier was "%c", call __builtin_putchar(arg). */ - else if (strcmp (fmt_str, target_percent_c) == 0) - { - if (! arglist - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE - || TREE_CHAIN (arglist)) - return 0; - fn = fn_putchar; - } - - if (!fn) - return 0; - - call = build_function_call_expr (fn, arglist); - return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call); } -/* Fold a call to the {,v}fprintf{,_unlocked} and __{,v}printf_chk builtins. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. FCODE is the BUILT_IN_* - code of the function to be simplified. */ +/* Returns true is EXP represents data that would potentially reside + in a readonly section. */ -static tree -fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore, - enum built_in_function fcode) +static bool +readonly_data_expr (tree exp) { - tree fp, fmt, fn = NULL_TREE, fn_fputc, fn_fputs, arg, call; - const char *fmt_str = NULL; - - /* If the return value is used, don't do the transformation. */ - if (! ignore) - return 0; - - /* Verify the required arguments in the original call. */ - if (! arglist) - return 0; - fp = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (fp))) - return 0; - arglist = TREE_CHAIN (arglist); - - if (fcode == BUILT_IN_FPRINTF_CHK || fcode == BUILT_IN_VFPRINTF_CHK) - { - tree flag; - - if (! arglist) - return 0; - flag = TREE_VALUE (arglist); - if (TREE_CODE (TREE_TYPE (flag)) != INTEGER_TYPE - || TREE_SIDE_EFFECTS (flag)) - return 0; - arglist = TREE_CHAIN (arglist); - } - - if (! arglist) - return 0; - fmt = TREE_VALUE (arglist); - if (! POINTER_TYPE_P (TREE_TYPE (fmt))) - return 0; - arglist = TREE_CHAIN (arglist); - - /* Check whether the format is a literal string constant. */ - fmt_str = c_getstr (fmt); - if (fmt_str == NULL) - return NULL_TREE; + STRIP_NOPS (exp); - if (fcode == BUILT_IN_FPRINTF_UNLOCKED) - { - /* If we're using an unlocked function, assume the other - unlocked functions exist explicitly. */ - fn_fputc = built_in_decls[BUILT_IN_FPUTC_UNLOCKED]; - fn_fputs = built_in_decls[BUILT_IN_FPUTS_UNLOCKED]; - } + if (TREE_CODE (exp) == ADDR_EXPR) + return decl_readonly_section (TREE_OPERAND (exp, 0), 0); else - { - fn_fputc = implicit_built_in_decls[BUILT_IN_FPUTC]; - fn_fputs = implicit_built_in_decls[BUILT_IN_FPUTS]; - } - - if (!init_target_chars()) - return 0; - - /* If the format doesn't contain % args or %%, use strcpy. */ - if (strchr (fmt_str, target_percent) == NULL) - { - if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK - && arglist) - return 0; - - /* If the format specifier was "", fprintf does nothing. */ - if (fmt_str[0] == '\0') - { - /* If FP has side-effects, just wait until gimplification is - done. */ - if (TREE_SIDE_EFFECTS (fp)) - return 0; - - return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0); - } - - /* When "string" doesn't contain %, replace all cases of - fprintf (fp, string) with fputs (string, fp). The fputs - builtin will take care of special cases like length == 1. */ - arglist = build_tree_list (NULL_TREE, fp); - arglist = tree_cons (NULL_TREE, fmt, arglist); - fn = fn_fputs; - } - - /* The other optimizations can be done only on the non-va_list variants. */ - else if (fcode == BUILT_IN_VFPRINTF || fcode == BUILT_IN_VFPRINTF_CHK) - return 0; - - /* If the format specifier was "%s", call __builtin_fputs (arg, fp). */ - else if (strcmp (fmt_str, target_percent_s) == 0) - { - if (! arglist - || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))) - || TREE_CHAIN (arglist)) - return 0; - arg = TREE_VALUE (arglist); - arglist = build_tree_list (NULL_TREE, fp); - arglist = tree_cons (NULL_TREE, arg, arglist); - fn = fn_fputs; - } - - /* If the format specifier was "%c", call __builtin_fputc (arg, fp). */ - else if (strcmp (fmt_str, target_percent_c) == 0) - { - if (! arglist - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE - || TREE_CHAIN (arglist)) - return 0; - arg = TREE_VALUE (arglist); - arglist = build_tree_list (NULL_TREE, fp); - arglist = tree_cons (NULL_TREE, arg, arglist); - fn = fn_fputc; - } - - if (!fn) - return 0; - - call = build_function_call_expr (fn, arglist); - return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call); -} - -/* Initialize format string characters in the target charset. */ - -static bool -init_target_chars (void) -{ - static bool init; - if (!init) - { - target_newline = lang_hooks.to_target_charset ('\n'); - target_percent = lang_hooks.to_target_charset ('%'); - target_c = lang_hooks.to_target_charset ('c'); - target_s = lang_hooks.to_target_charset ('s'); - if (target_newline == 0 || target_percent == 0 || target_c == 0 - || target_s == 0) - return false; - - target_percent_c[0] = target_percent; - target_percent_c[1] = target_c; - target_percent_c[2] = '\0'; - - target_percent_s[0] = target_percent; - target_percent_s[1] = target_s; - target_percent_s[2] = '\0'; - - target_percent_s_newline[0] = target_percent; - target_percent_s_newline[1] = target_s; - target_percent_s_newline[2] = target_newline; - target_percent_s_newline[3] = '\0'; - - init = true; - } - return true; + return false; } diff --git a/contrib/gcc/c-common.c b/contrib/gcc/c-common.c index b5ea608..7305b3c6 100644 --- a/contrib/gcc/c-common.c +++ b/contrib/gcc/c-common.c @@ -1,6 +1,6 @@ /* Subroutines shared by all languages that are variants of C. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #include "config.h" #include "system.h" @@ -42,12 +42,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "tree-inline.h" #include "c-tree.h" #include "toplev.h" -#include "tree-iterator.h" -#include "hashtab.h" -#include "tree-mudflap.h" -#include "opts.h" -#include "real.h" -#include "cgraph.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ @@ -61,10 +55,6 @@ cpp_reader *parse_in; /* Declared in c-pragma.h. */ #define SIZE_TYPE "long unsigned int" #endif -#ifndef PID_TYPE -#define PID_TYPE "int" -#endif - #ifndef WCHAR_TYPE #define WCHAR_TYPE "int" #endif @@ -131,10 +121,6 @@ cpp_reader *parse_in; /* Declared in c-pragma.h. */ tree complex_double_type_node; tree complex_long_double_type_node; - tree dfloat32_type_node; - tree dfloat64_type_node; - tree_dfloat128_type_node; - tree intQI_type_node; tree intHI_type_node; tree intSI_type_node; @@ -196,6 +182,11 @@ cpp_reader *parse_in; /* Declared in c-pragma.h. */ */ tree c_global_trees[CTI_MAX]; + +/* TRUE if a code represents a statement. The front end init + langhook should take care of initialization of this array. */ + +bool statement_code_p[MAX_TREE_CODES]; /* Switches common to the C front ends. */ @@ -220,10 +211,6 @@ char flag_dump_macros; char flag_dump_includes; -/* Nonzero means process PCH files while preprocessing. */ - -bool flag_pch_preprocess; - /* The file name to which we should write a precompiled header, or NULL if no header will be written in this compile. */ @@ -261,9 +248,78 @@ int flag_ms_extensions; int flag_no_asm; +/* Nonzero means give string constants the type `const char *', as mandated + by the standard. */ + +int flag_const_strings; + /* Nonzero means to treat bitfields as signed unless they say `unsigned'. */ int flag_signed_bitfields = 1; +int explicit_flag_signed_bitfields; + +/* Nonzero means warn about pointer casts that can drop a type qualifier + from the pointer target type. */ + +int warn_cast_qual; + +/* Warn about functions which might be candidates for format attributes. */ + +int warn_missing_format_attribute; + +/* Nonzero means warn about sizeof(function) or addition/subtraction + of function pointers. */ + +int warn_pointer_arith; + +/* Nonzero means do not warn that K&R style main() is not a function prototype. */ + +int flag_bsd_no_warn_kr_main; + +/* Nonzero means warn for any global function def + without separate previous prototype decl. */ + +int warn_missing_prototypes; + +/* Warn if adding () is suggested. */ + +int warn_parentheses; + +/* Warn if initializer is not completely bracketed. */ + +int warn_missing_braces; + +/* Warn about comparison of signed and unsigned values. + If -1, neither -Wsign-compare nor -Wno-sign-compare has been specified + (in which case -Wextra gets to decide). */ + +int warn_sign_compare = -1; + +/* Nonzero means warn about usage of long long when `-pedantic'. */ + +int warn_long_long = 1; + +/* Nonzero means warn about deprecated conversion from string constant to + `char *'. */ + +int warn_write_strings; + +/* Nonzero means warn about multiple (redundant) decls for the same single + variable or function. */ + +int warn_redundant_decls; + +/* Warn about testing equality of floating point numbers. */ + +int warn_float_equal; + +/* Warn about a subscript that has type char. */ + +int warn_char_subscripts; + +/* Warn if a type conversion is done that might have confusing results. */ + +int warn_conversion; /* Warn about #pragma directives that are not recognized. */ @@ -274,17 +330,35 @@ int warn_unknown_pragmas; /* Tri state variable. */ int warn_format; -/* Warn about using __null (as NULL in C++) as sentinel. For code compiled - with GCC this doesn't matter as __null is guaranteed to have the right - size. */ +/* Warn about Y2K problems with strftime formats. */ + +int warn_format_y2k; + +/* Warn about excess arguments to formats. */ -int warn_strict_null_sentinel; +int warn_format_extra_args; + +/* Warn about zero-length formats. */ + +int warn_format_zero_length; + +/* Warn about non-literal format arguments. */ + +int warn_format_nonliteral; + +/* Warn about possible security problems with calls to format functions. */ + +int warn_format_security; /* Zero means that faster, ...NonNil variants of objc_msgSend... calls will be used in ObjC; passing nil receivers to such calls will most likely result in crashes. */ int flag_nil_receivers = 1; +/* Nonzero means that we will allow new ObjC exception syntax (@throw, + @try, etc.) in source code. */ +int flag_objc_exceptions = 0; + /* Nonzero means that code generation will be altered to support "zero-link" execution. This currently affects ObjC only, but may affect other languages in the future. */ @@ -294,10 +368,15 @@ int flag_zero_link = 0; unit. It will inform the ObjC runtime that class definition(s) herein contained are to replace one(s) previously loaded. */ int flag_replace_objc_classes = 0; - + /* C/ObjC language option variables. */ +/* Nonzero means message about use of implicit function declarations; + 1 means warning; 2 means error. */ + +int mesg_implicit_function_declaration = -1; + /* Nonzero means allow type mismatches in conditional expressions; just make their values `void'. */ @@ -311,14 +390,75 @@ int flag_isoc94; int flag_isoc99; +/* Nonzero means allow the BSD kernel printf enhancements. */ + +int flag_bsd_format; + /* Nonzero means that we have builtin functions, and main is an int. */ int flag_hosted = 1; +/* Nonzero means warn when casting a function call to a type that does + not match the return type (e.g. (float)sqrt() or (anything*)malloc() + when there is no previous declaration of sqrt or malloc. */ + +int warn_bad_function_cast; + +/* Warn about traditional constructs whose meanings changed in ANSI C. */ + +int warn_traditional; + +/* Nonzero means warn for a declaration found after a statement. */ + +int warn_declaration_after_statement; + +/* Nonzero means warn for non-prototype function decls + or non-prototyped defs without previous prototype. */ + +int warn_strict_prototypes; + +/* Nonzero means warn for any global function def + without separate previous decl. */ + +int warn_missing_declarations; + +/* Nonzero means warn about declarations of objects not at + file-scope level and about *all* declarations of functions (whether + or static) not at file-scope level. Note that we exclude + implicit function declarations. To get warnings about those, use + -Wimplicit. */ + +int warn_nested_externs; + /* Warn if main is suspicious. */ int warn_main; +/* Nonzero means warn about possible violations of sequence point rules. */ + +int warn_sequence_point; + +/* Nonzero means warn about uninitialized variable when it is initialized with itself. + For example: int i = i;, GCC will not warn about this when warn_init_self is nonzero. */ + +int warn_init_self; + +/* Nonzero means to warn about compile-time division by zero. */ +int warn_div_by_zero = 1; + +/* Nonzero means warn about use of implicit int. */ + +int warn_implicit_int; + +/* Warn about NULL being passed to argument slots marked as requiring + non-NULL. */ + +int warn_nonnull; + +/* Warn about old-style parameter declaration. */ + +int warn_old_style_definition; + /* ObjC language option variables. */ @@ -328,16 +468,43 @@ int warn_main; int flag_gen_declaration; +/* Generate code for GNU or NeXT runtime environment. */ + +#ifdef NEXT_OBJC_RUNTIME +int flag_next_runtime = 1; +#else +int flag_next_runtime = 0; +#endif + /* Tells the compiler that this is a special run. Do not perform any compiling, instead we are to test some platform dependent features and output a C header file with appropriate definitions. */ int print_struct_values; -/* Tells the compiler what is the constant string class for Objc. */ +/* ???. Undocumented. */ const char *constant_string_class_name; +/* Warn if multiple methods are seen for the same selector, but with + different argument types. Performs the check on the whole selector + table at the end of compilation. */ + +int warn_selector; + +/* Warn if a @selector() is found, and no method with that selector + has been previously declared. The check is done on each + @selector() as soon as it is found - so it warns about forward + declarations. */ + +int warn_undeclared_selector; + +/* Warn if methods required by a protocol are not implemented in the + class adopting it. When turned off, methods inherited to that + class are also considered implemented. */ + +int warn_protocol = 1; + /* C++ language option variables. */ @@ -424,16 +591,10 @@ int flag_weak = 1; int flag_working_directory = -1; /* Nonzero to use __cxa_atexit, rather than atexit, to register - destructors for local statics and global objects. '2' means it has been - set nonzero as a default, not by a command-line flag. */ + destructors for local statics and global objects. */ int flag_use_cxa_atexit = DEFAULT_USE_CXA_ATEXIT; -/* Nonzero to use __cxa_get_exception_ptr in C++ exception-handling - code. '2' means it has not been set explicitly on the command line. */ - -int flag_use_cxa_get_exception_ptr = 2; - /* Nonzero means make the default pedwarns warnings instead of errors. The value of this flag is ignored if -pedantic is specified. */ @@ -446,15 +607,70 @@ int flag_permissive; int flag_enforce_eh_specs = 1; -/* Nonzero means to generate thread-safe code for initializing local - statics. */ +/* Nonzero means warn about things that will change when compiling + with an ABI-compliant compiler. */ + +int warn_abi = 0; -int flag_threadsafe_statics = 1; +/* Nonzero means warn about invalid uses of offsetof. */ + +int warn_invalid_offsetof = 1; /* Nonzero means warn about implicit declarations. */ int warn_implicit = 1; +/* Nonzero means warn when all ctors or dtors are private, and the class + has no friends. */ + +int warn_ctor_dtor_privacy = 0; + +/* Nonzero means warn in function declared in derived class has the + same name as a virtual in the base class, but fails to match the + type signature of any virtual function in the base class. */ + +int warn_overloaded_virtual; + +/* Nonzero means warn when declaring a class that has a non virtual + destructor, when it really ought to have a virtual one. */ + +int warn_nonvdtor; + +/* Nonzero means warn when the compiler will reorder code. */ + +int warn_reorder; + +/* Nonzero means warn when synthesis behavior differs from Cfront's. */ + +int warn_synth; + +/* Nonzero means warn when we convert a pointer to member function + into a pointer to (void or function). */ + +int warn_pmf2ptr = 1; + +/* Nonzero means warn about violation of some Effective C++ style rules. */ + +int warn_ecpp; + +/* Nonzero means warn where overload resolution chooses a promotion from + unsigned to signed over a conversion to an unsigned of the same size. */ + +int warn_sign_promo; + +/* Nonzero means warn when an old-style cast is used. */ + +int warn_old_style_cast; + +/* Nonzero means warn when non-templatized friend functions are + declared within a template */ + +int warn_nontemplate_friend = 1; + +/* Nonzero means complain about deprecated features. */ + +int warn_deprecated = 1; + /* Maximum template instantiation depth. This limit is rather arbitrary, but it exists to limit the time it takes to notice infinite template instantiations. */ @@ -469,6 +685,10 @@ tree *ridpointers; tree (*make_fname_decl) (tree, int); +/* If non-NULL, the address of a language-specific function that takes + any action required right before expand_function_end is called. */ +void (*lang_expand_function_end) (void); + /* Nonzero means the expression being parsed will never be evaluated. This is a count, since unevaluated expressions can nest. */ int skip_evaluation; @@ -495,8 +715,27 @@ const struct fname_var_t fname_vars[] = }; static int constant_fits_type_p (tree, tree); -static tree check_case_value (tree); -static bool check_case_bounds (tree, tree, tree *, tree *); + +/* Keep a stack of if statements. We record the number of compound + statements seen up to the if keyword, as well as the line number + and file of the if. If a potentially ambiguous else is seen, that + fact is recorded; the warning is issued when we can be sure that + the enclosing if statement does not have an else branch. */ +typedef struct +{ + int compstmt_count; + location_t locus; + int needs_warning; + tree if_stmt; +} if_elt; + +static if_elt *if_stack; + +/* Amount of space in the if statement stack. */ +static int if_stack_space = 0; + +/* Stack pointer. */ +static int if_stack_pointer = 0; static tree handle_packed_attribute (tree *, tree, tree, int, bool *); static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *); @@ -505,13 +744,8 @@ static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); static tree handle_always_inline_attribute (tree *, tree, tree, int, bool *); -static tree handle_gnu_inline_attribute (tree *, tree, tree, int, - bool *); -static tree handle_flatten_attribute (tree *, tree, tree, int, bool *); static tree handle_used_attribute (tree *, tree, tree, int, bool *); static tree handle_unused_attribute (tree *, tree, tree, int, bool *); -static tree handle_externally_visible_attribute (tree *, tree, tree, int, - bool *); static tree handle_const_attribute (tree *, tree, tree, int, bool *); static tree handle_transparent_union_attribute (tree *, tree, tree, int, bool *); @@ -522,7 +756,6 @@ static tree handle_section_attribute (tree *, tree, tree, int, bool *); static tree handle_aligned_attribute (tree *, tree, tree, int, bool *); static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ; static tree handle_alias_attribute (tree *, tree, tree, int, bool *); -static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ; static tree handle_visibility_attribute (tree *, tree, tree, int, bool *); static tree handle_tls_model_attribute (tree *, tree, tree, int, @@ -530,11 +763,9 @@ static tree handle_tls_model_attribute (tree *, tree, tree, int, static tree handle_no_instrument_function_attribute (tree *, tree, tree, int, bool *); static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); -static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); static tree handle_no_limit_stack_attribute (tree *, tree, tree, int, bool *); static tree handle_pure_attribute (tree *, tree, tree, int, bool *); -static tree handle_novops_attribute (tree *, tree, tree, int, bool *); static tree handle_deprecated_attribute (tree *, tree, tree, int, bool *); static tree handle_vector_size_attribute (tree *, tree, tree, int, @@ -544,7 +775,6 @@ static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *); static tree handle_warn_unused_result_attribute (tree *, tree, tree, int, bool *); -static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); static void check_function_nonnull (tree, tree); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); @@ -575,16 +805,10 @@ const struct attribute_spec c_common_attribute_table[] = handle_noinline_attribute }, { "always_inline", 0, 0, true, false, false, handle_always_inline_attribute }, - { "gnu_inline", 0, 0, true, false, false, - handle_gnu_inline_attribute }, - { "flatten", 0, 0, true, false, false, - handle_flatten_attribute }, { "used", 0, 0, true, false, false, handle_used_attribute }, { "unused", 0, 0, false, false, false, handle_unused_attribute }, - { "externally_visible", 0, 0, true, false, false, - handle_externally_visible_attribute }, /* The same comments as for noreturn attributes apply to const ones. */ { "const", 0, 0, true, false, false, handle_const_attribute }, @@ -604,27 +828,19 @@ const struct attribute_spec c_common_attribute_table[] = handle_weak_attribute }, { "alias", 1, 1, true, false, false, handle_alias_attribute }, - { "weakref", 0, 1, true, false, false, - handle_weakref_attribute }, { "no_instrument_function", 0, 0, true, false, false, handle_no_instrument_function_attribute }, { "malloc", 0, 0, true, false, false, handle_malloc_attribute }, - { "returns_twice", 0, 0, true, false, false, - handle_returns_twice_attribute }, { "no_stack_limit", 0, 0, true, false, false, handle_no_limit_stack_attribute }, { "pure", 0, 0, true, false, false, handle_pure_attribute }, - /* For internal use (marking of builtins) only. The name contains space - to prevent its usage in source code. */ - { "no vops", 0, 0, true, false, false, - handle_novops_attribute }, { "deprecated", 0, 0, false, false, false, handle_deprecated_attribute }, { "vector_size", 1, 1, false, true, false, handle_vector_size_attribute }, - { "visibility", 1, 1, false, false, false, + { "visibility", 1, 1, true, false, false, handle_visibility_attribute }, { "tls_model", 1, 1, true, false, false, handle_tls_model_attribute }, @@ -637,8 +853,6 @@ const struct attribute_spec c_common_attribute_table[] = handle_cleanup_attribute }, { "warn_unused_result", 0, 0, false, true, true, handle_warn_unused_result_attribute }, - { "sentinel", 0, 1, false, true, true, - handle_sentinel_attribute }, { NULL, 0, 0, false, false, false, NULL } }; @@ -655,6 +869,131 @@ const struct attribute_spec c_common_format_attribute_table[] = { NULL, 0, 0, false, false, false, NULL } }; +/* Record the start of an if-then, and record the start of it + for ambiguous else detection. + + COND is the condition for the if-then statement. + + IF_STMT is the statement node that has already been created for + this if-then statement. It is created before parsing the + condition to keep line number information accurate. */ + +void +c_expand_start_cond (tree cond, int compstmt_count, tree if_stmt) +{ + /* Make sure there is enough space on the stack. */ + if (if_stack_space == 0) + { + if_stack_space = 10; + if_stack = xmalloc (10 * sizeof (if_elt)); + } + else if (if_stack_space == if_stack_pointer) + { + if_stack_space += 10; + if_stack = xrealloc (if_stack, if_stack_space * sizeof (if_elt)); + } + + IF_COND (if_stmt) = cond; + add_stmt (if_stmt); + + /* Record this if statement. */ + if_stack[if_stack_pointer].compstmt_count = compstmt_count; + if_stack[if_stack_pointer].locus = input_location; + if_stack[if_stack_pointer].needs_warning = 0; + if_stack[if_stack_pointer].if_stmt = if_stmt; + if_stack_pointer++; +} + +/* Called after the then-clause for an if-statement is processed. */ + +void +c_finish_then (void) +{ + tree if_stmt = if_stack[if_stack_pointer - 1].if_stmt; + RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt)); +} + +/* Record the end of an if-then. Optionally warn if a nested + if statement had an ambiguous else clause. */ + +void +c_expand_end_cond (void) +{ + if_stack_pointer--; + if (if_stack[if_stack_pointer].needs_warning) + warning ("%Hsuggest explicit braces to avoid ambiguous `else'", + &if_stack[if_stack_pointer].locus); + last_expr_type = NULL_TREE; +} + +/* Called between the then-clause and the else-clause + of an if-then-else. */ + +void +c_expand_start_else (void) +{ + /* An ambiguous else warning must be generated for the enclosing if + statement, unless we see an else branch for that one, too. */ + if (warn_parentheses + && if_stack_pointer > 1 + && (if_stack[if_stack_pointer - 1].compstmt_count + == if_stack[if_stack_pointer - 2].compstmt_count)) + if_stack[if_stack_pointer - 2].needs_warning = 1; + + /* Even if a nested if statement had an else branch, it can't be + ambiguous if this one also has an else. So don't warn in that + case. Also don't warn for any if statements nested in this else. */ + if_stack[if_stack_pointer - 1].needs_warning = 0; + if_stack[if_stack_pointer - 1].compstmt_count--; +} + +/* Called after the else-clause for an if-statement is processed. */ + +void +c_finish_else (void) +{ + tree if_stmt = if_stack[if_stack_pointer - 1].if_stmt; + RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt)); +} + +/* Begin an if-statement. Returns a newly created IF_STMT if + appropriate. + + Unlike the C++ front-end, we do not call add_stmt here; it is + probably safe to do so, but I am not very familiar with this + code so I am being extra careful not to change its behavior + beyond what is strictly necessary for correctness. */ + +tree +c_begin_if_stmt (void) +{ + tree r; + r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE); + return r; +} + +/* Begin a while statement. Returns a newly created WHILE_STMT if + appropriate. + + Unlike the C++ front-end, we do not call add_stmt here; it is + probably safe to do so, but I am not very familiar with this + code so I am being extra careful not to change its behavior + beyond what is strictly necessary for correctness. */ + +tree +c_begin_while_stmt (void) +{ + tree r; + r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE); + return r; +} + +void +c_finish_while_stmt_cond (tree cond, tree while_stmt) +{ + WHILE_COND (while_stmt) = cond; +} + /* Push current bindings for the function name VAR_DECLS. */ void @@ -669,7 +1008,7 @@ start_fname_decls (void) if (decl) { - saved = tree_cons (decl, build_int_cst (NULL_TREE, ix), saved); + saved = tree_cons (decl, build_int_2 (ix, 0), saved); *fname_vars[ix].decl = NULL_TREE; } } @@ -680,30 +1019,43 @@ start_fname_decls (void) saved_function_name_decls); } -/* Finish up the current bindings, adding them into the current function's - statement tree. This must be done _before_ finish_stmt_tree is called. - If there is no current function, we must be at file scope and no statements - are involved. Pop the previous bindings. */ +/* Finish up the current bindings, adding them into the + current function's statement tree. This is done by wrapping the + function's body in a COMPOUND_STMT containing these decls too. This + must be done _before_ finish_stmt_tree is called. If there is no + current function, we must be at file scope and no statements are + involved. Pop the previous bindings. */ void finish_fname_decls (void) { unsigned ix; - tree stmts = NULL_TREE; + tree body = NULL_TREE; tree stack = saved_function_name_decls; for (; stack && TREE_VALUE (stack); stack = TREE_CHAIN (stack)) - append_to_statement_list (TREE_VALUE (stack), &stmts); + body = chainon (TREE_VALUE (stack), body); - if (stmts) + if (body) { - tree *bodyp = &DECL_SAVED_TREE (current_function_decl); + /* They were called into existence, so add to statement tree. Add + the DECL_STMTs inside the outermost scope. */ + tree *p = &DECL_SAVED_TREE (current_function_decl); + /* Skip the dummy EXPR_STMT and any EH_SPEC_BLOCK. */ + while (TREE_CODE (*p) != COMPOUND_STMT) + { + if (TREE_CODE (*p) == EXPR_STMT) + p = &TREE_CHAIN (*p); + else + p = &TREE_OPERAND(*p, 0); + } - if (TREE_CODE (*bodyp) == BIND_EXPR) - bodyp = &BIND_EXPR_BODY (*bodyp); + p = &COMPOUND_BODY (*p); + if (TREE_CODE (*p) == SCOPE_STMT) + p = &TREE_CHAIN (*p); - append_to_statement_list_force (*bodyp, &stmts); - *bodyp = stmts; + body = chainon (body, *p); + *p = body; } for (ix = 0; fname_vars[ix].decl; ix++) @@ -727,68 +1079,26 @@ finish_fname_decls (void) } /* Return the text name of the current function, suitably prettified - by PRETTY_P. Return string must be freed by caller. */ + by PRETTY_P. */ const char * fname_as_string (int pretty_p) { const char *name = "top level"; - char *namep; int vrb = 2; - if (!pretty_p) + if (! pretty_p) { name = ""; vrb = 0; } if (current_function_decl) - name = lang_hooks.decl_printable_name (current_function_decl, vrb); - - if (c_lex_string_translate) - { - int len = strlen (name) + 3; /* Two for '"'s. One for NULL. */ - cpp_string cstr = { 0, 0 }, strname; - - namep = XNEWVEC (char, len); - snprintf (namep, len, "\"%s\"", name); - strname.text = (unsigned char *) namep; - strname.len = len - 1; - - if (cpp_interpret_string (parse_in, &strname, 1, &cstr, false)) - { - XDELETEVEC (namep); - return (char *) cstr.text; - } - } - else - namep = xstrdup (name); + name = (*lang_hooks.decl_printable_name) (current_function_decl, vrb); - return namep; + return name; } -/* Expand DECL if it declares an entity not handled by the - common code. */ - -int -c_expand_decl (tree decl) -{ - if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl)) - { - /* Let the back-end know about this variable. */ - if (!anon_aggr_type_p (TREE_TYPE (decl))) - emit_local_var (decl); - else - expand_anon_union_decl (decl, NULL_TREE, - DECL_ANON_UNION_ELEMS (decl)); - } - else - return 0; - - return 1; -} - - /* Return the VAR_DECL for a const char array naming the current function. If the VAR_DECL has not yet been created, create it now. RID indicates how it should be formatted and IDENTIFIER_NODE @@ -809,30 +1119,33 @@ fname_decl (unsigned int rid, tree id) decl = *fname_vars[ix].decl; if (!decl) { + tree saved_last_tree = last_tree; /* If a tree is built here, it would normally have the lineno of the current statement. Later this tree will be moved to the beginning of the function and this line number will be wrong. To avoid this problem set the lineno to 0 here; that prevents it from appearing in the RTL. */ - tree stmts; - location_t saved_location = input_location; -#ifdef USE_MAPPED_LOCATION - input_location = UNKNOWN_LOCATION; -#else + int saved_lineno = input_line; input_line = 0; -#endif - stmts = push_stmt_list (); decl = (*make_fname_decl) (id, fname_vars[ix].pretty); - stmts = pop_stmt_list (stmts); - if (!IS_EMPTY_STMT (stmts)) - saved_function_name_decls - = tree_cons (decl, stmts, saved_function_name_decls); + if (last_tree != saved_last_tree) + { + /* We created some statement tree for the decl. This belongs + at the start of the function, so remove it now and reinsert + it after the function is complete. */ + tree stmts = TREE_CHAIN (saved_last_tree); + + TREE_CHAIN (saved_last_tree) = NULL_TREE; + last_tree = saved_last_tree; + saved_function_name_decls = tree_cons (decl, stmts, + saved_function_name_decls); + } *fname_vars[ix].decl = decl; - input_location = saved_location; + input_line = saved_lineno; } if (!ix && !current_function_decl) - pedwarn ("%qD is not defined outside of function scope", decl); + pedwarn ("'%D' is not defined outside of function scope", decl); return decl; } @@ -844,56 +1157,37 @@ fix_string_type (tree value) { const int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT; const int wide_flag = TREE_TYPE (value) == wchar_array_type_node; + const int nchars_max = flag_isoc99 ? 4095 : 509; int length = TREE_STRING_LENGTH (value); int nchars; - tree e_type, i_type, a_type; /* Compute the number of elements, for the array type. */ nchars = wide_flag ? length / wchar_bytes : length; - /* C89 2.2.4.1, C99 5.2.4.1 (Translation limits). The analogous - limit in C++98 Annex B is very large (65536) and is not normative, - so we do not diagnose it (warn_overlength_strings is forced off - in c_common_post_options). */ - if (warn_overlength_strings) - { - const int nchars_max = flag_isoc99 ? 4095 : 509; - const int relevant_std = flag_isoc99 ? 99 : 90; - if (nchars - 1 > nchars_max) - /* Translators: The %d after 'ISO C' will be 90 or 99. Do not - separate the %d from the 'C'. 'ISO' should not be - translated, but it may be moved after 'C%d' in languages - where modifiers follow nouns. */ - pedwarn ("string length %qd is greater than the length %qd " - "ISO C%d compilers are required to support", - nchars - 1, nchars_max, relevant_std); - } - - /* Create the array type for the string constant. The ISO C++ - standard says that a string literal has type `const char[N]' or - `const wchar_t[N]'. We use the same logic when invoked as a C - front-end with -Wwrite-strings. - ??? We should change the type of an expression depending on the - state of a warning flag. We should just be warning -- see how - this is handled in the C++ front-end for the deprecated implicit - conversion from string literals to `char*' or `wchar_t*'. - - The C++ front end relies on TYPE_MAIN_VARIANT of a cv-qualified - array type being the unqualified version of that type. - Therefore, if we are constructing an array of const char, we must - construct the matching unqualified array type first. The C front - end does not require this, but it does no harm, so we do it - unconditionally. */ - e_type = wide_flag ? wchar_type_node : char_type_node; - i_type = build_index_type (build_int_cst (NULL_TREE, nchars - 1)); - a_type = build_array_type (e_type, i_type); - if (c_dialect_cxx() || warn_write_strings) - a_type = c_build_qualified_type (a_type, TYPE_QUAL_CONST); - - TREE_TYPE (value) = a_type; + if (pedantic && nchars - 1 > nchars_max && !c_dialect_cxx ()) + pedwarn ("string length `%d' is greater than the length `%d' ISO C%d compilers are required to support", + nchars - 1, nchars_max, flag_isoc99 ? 99 : 89); + + /* Create the array type for the string constant. + -Wwrite-strings says make the string constant an array of const char + so that copying it to a non-const pointer will get a warning. + For C++, this is the standard behavior. */ + if (flag_const_strings && ! flag_writable_strings) + { + tree elements + = build_type_variant (wide_flag ? wchar_type_node : char_type_node, + 1, 0); + TREE_TYPE (value) + = build_array_type (elements, + build_index_type (build_int_2 (nchars - 1, 0))); + } + else + TREE_TYPE (value) + = build_array_type (wide_flag ? wchar_type_node : char_type_node, + build_index_type (build_int_2 (nchars - 1, 0))); + TREE_CONSTANT (value) = 1; - TREE_INVARIANT (value) = 1; - TREE_READONLY (value) = 1; + TREE_READONLY (value) = ! flag_writable_strings; TREE_STATIC (value) = 1; return value; } @@ -910,9 +1204,7 @@ constant_expression_warning (tree value) if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST || TREE_CODE (value) == VECTOR_CST || TREE_CODE (value) == COMPLEX_CST) - && TREE_CONSTANT_OVERFLOW (value) - && warn_overflow - && pedantic) + && TREE_CONSTANT_OVERFLOW (value) && pedantic) pedwarn ("overflow in constant expression"); } @@ -933,7 +1225,7 @@ overflow_warning (tree value) { TREE_OVERFLOW (value) = 0; if (skip_evaluation == 0) - warning (OPT_Woverflow, "integer overflow in expression"); + warning ("integer overflow in expression"); } else if ((TREE_CODE (value) == REAL_CST || (TREE_CODE (value) == COMPLEX_CST @@ -942,13 +1234,13 @@ overflow_warning (tree value) { TREE_OVERFLOW (value) = 0; if (skip_evaluation == 0) - warning (OPT_Woverflow, "floating point overflow in expression"); + warning ("floating point overflow in expression"); } else if (TREE_CODE (value) == VECTOR_CST && TREE_OVERFLOW (value)) { TREE_OVERFLOW (value) = 0; if (skip_evaluation == 0) - warning (OPT_Woverflow, "vector overflow in expression"); + warning ("vector overflow in expression"); } } @@ -957,93 +1249,25 @@ overflow_warning (tree value) Invoke this function on every expression that might be implicitly converted to an unsigned type. */ -static void +void unsigned_conversion_warning (tree result, tree operand) { tree type = TREE_TYPE (result); if (TREE_CODE (operand) == INTEGER_CST && TREE_CODE (type) == INTEGER_TYPE - && TYPE_UNSIGNED (type) + && TREE_UNSIGNED (type) && skip_evaluation == 0 && !int_fits_type_p (operand, type)) { if (!int_fits_type_p (operand, c_common_signed_type (type))) /* This detects cases like converting -129 or 256 to unsigned char. */ - warning (OPT_Woverflow, - "large integer implicitly truncated to unsigned type"); - else - warning (OPT_Wconversion, - "negative integer implicitly converted to unsigned type"); + warning ("large integer implicitly truncated to unsigned type"); + else if (warn_conversion) + warning ("negative integer implicitly converted to unsigned type"); } } -/* Print a warning about casts that might indicate violation - of strict aliasing rules if -Wstrict-aliasing is used and - strict aliasing mode is in effect. OTYPE is the original - TREE_TYPE of EXPR, and TYPE the type we're casting to. */ - -void -strict_aliasing_warning (tree otype, tree type, tree expr) -{ - if (flag_strict_aliasing && warn_strict_aliasing - && POINTER_TYPE_P (type) && POINTER_TYPE_P (otype) - && TREE_CODE (expr) == ADDR_EXPR - && (DECL_P (TREE_OPERAND (expr, 0)) - || handled_component_p (TREE_OPERAND (expr, 0))) - && !VOID_TYPE_P (TREE_TYPE (type))) - { - /* Casting the address of an object to non void pointer. Warn - if the cast breaks type based aliasing. */ - if (!COMPLETE_TYPE_P (TREE_TYPE (type))) - warning (OPT_Wstrict_aliasing, "type-punning to incomplete type " - "might break strict-aliasing rules"); - else - { - HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0))); - HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type)); - - if (!alias_sets_conflict_p (set1, set2)) - warning (OPT_Wstrict_aliasing, "dereferencing type-punned " - "pointer will break strict-aliasing rules"); - else if (warn_strict_aliasing > 1 - && !alias_sets_might_conflict_p (set1, set2)) - warning (OPT_Wstrict_aliasing, "dereferencing type-punned " - "pointer might break strict-aliasing rules"); - } - } -} - - -/* Print a warning about if (); or if () .. else; constructs - via the special empty statement node that we create. INNER_THEN - and INNER_ELSE are the statement lists of the if and the else - block. */ - -void -empty_body_warning (tree inner_then, tree inner_else) -{ - if (extra_warnings) - { - if (TREE_CODE (inner_then) == STATEMENT_LIST - && STATEMENT_LIST_TAIL (inner_then)) - inner_then = STATEMENT_LIST_TAIL (inner_then)->stmt; - - if (inner_else && TREE_CODE (inner_else) == STATEMENT_LIST - && STATEMENT_LIST_TAIL (inner_else)) - inner_else = STATEMENT_LIST_TAIL (inner_else)->stmt; - - if (IS_EMPTY_STMT (inner_then) && !inner_else) - warning (OPT_Wextra, "%Hempty body in an if-statement", - EXPR_LOCUS (inner_then)); - - if (inner_else && IS_EMPTY_STMT (inner_else)) - warning (OPT_Wextra, "%Hempty body in an else-statement", - EXPR_LOCUS (inner_else)); - } -} - - /* Nonzero if constant C has a value that is permissible for type TYPE (an INTEGER_TYPE). */ @@ -1064,9 +1288,7 @@ vector_types_convertible_p (tree t1, tree t2) { return targetm.vector_opaque_p (t1) || targetm.vector_opaque_p (t2) - || (tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)) - && (TREE_CODE (TREE_TYPE (t1)) != REAL_TYPE || - TYPE_PRECISION (t1) == TYPE_PRECISION (t2)) + || (tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)) && INTEGRAL_TYPE_P (TREE_TYPE (t1)) == INTEGRAL_TYPE_P (TREE_TYPE (t2))); } @@ -1087,22 +1309,20 @@ convert_and_check (tree type, tree expr) /* Do not diagnose overflow in a constant expression merely because a conversion overflowed. */ - TREE_CONSTANT_OVERFLOW (t) = CONSTANT_CLASS_P (expr) - && TREE_CONSTANT_OVERFLOW (expr); + TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (expr); /* No warning for converting 0x80000000 to int. */ - if (!(TYPE_UNSIGNED (type) < TYPE_UNSIGNED (TREE_TYPE (expr)) + if (!(TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (expr)) && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr)))) /* If EXPR fits in the unsigned version of TYPE, don't warn unless pedantic. */ if ((pedantic - || TYPE_UNSIGNED (type) - || !constant_fits_type_p (expr, - c_common_unsigned_type (type))) - && skip_evaluation == 0) - warning (OPT_Woverflow, - "overflow in implicit constant conversion"); + || TREE_UNSIGNED (type) + || ! constant_fits_type_p (expr, + c_common_unsigned_type (type))) + && skip_evaluation == 0) + warning ("overflow in implicit constant conversion"); } else unsigned_conversion_warning (t, expr); @@ -1148,13 +1368,14 @@ static int warning_candidate_p (tree); static void warn_for_collisions (struct tlist *); static void warn_for_collisions_1 (tree, tree, struct tlist *, int); static struct tlist *new_tlist (struct tlist *, tree, tree); +static void verify_sequence_points (tree); /* Create a new struct tlist and fill in its fields. */ static struct tlist * new_tlist (struct tlist *next, tree t, tree writer) { struct tlist *l; - l = XOBNEW (&tlist_obstack, struct tlist); + l = obstack_alloc (&tlist_obstack, sizeof *l); l->next = next; l->expr = t; l->writer = writer; @@ -1170,9 +1391,9 @@ add_tlist (struct tlist **to, struct tlist *add, tree exclude_writer, int copy) while (add) { struct tlist *next = add->next; - if (!copy) + if (! copy) add->next = *to; - if (!exclude_writer || add->writer != exclude_writer) + if (! exclude_writer || add->writer != exclude_writer) *to = copy ? new_tlist (*to, add->expr, add->writer) : add; add = next; } @@ -1202,10 +1423,10 @@ merge_tlist (struct tlist **to, struct tlist *add, int copy) if (tmp2->expr == add->expr) { found = 1; - if (!tmp2->writer) + if (! tmp2->writer) tmp2->writer = add->writer; } - if (!found) + if (! found) { *end = copy ? add : new_tlist (NULL, add->expr, add->writer); end = &(*end)->next; @@ -1234,11 +1455,11 @@ warn_for_collisions_1 (tree written, tree writer, struct tlist *list, { if (list->expr == written && list->writer != writer - && (!only_writes || list->writer) - && DECL_NAME (list->expr)) + && (! only_writes || list->writer)) { warned_ids = new_tlist (warned_ids, written, NULL_TREE); - warning (0, "operation on %qE may be undefined", list->expr); + warning ("operation on `%s' may be undefined", + IDENTIFIER_POINTER (DECL_NAME (list->expr))); } list = list->next; } @@ -1298,7 +1519,7 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp, { struct tlist *tmp_before, *tmp_nosp, *tmp_list2, *tmp_list3; enum tree_code code; - enum tree_code_class cl; + char class; /* X may be NULL if it is the operand of an empty statement expression ({ }). */ @@ -1307,7 +1528,7 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp, restart: code = TREE_CODE (x); - cl = TREE_CODE_CLASS (code); + class = TREE_CODE_CLASS (code); if (warning_candidate_p (x)) { @@ -1422,9 +1643,9 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp, if (t->expr == x) break; - if (!t) + if (! t) { - t = XOBNEW (&tlist_obstack, struct tlist_cache); + t = obstack_alloc (&tlist_obstack, sizeof *t); t->next = save_expr_cache; t->expr = x; save_expr_cache = t; @@ -1447,37 +1668,47 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp, add_tlist (pno_sp, t->cache_after_sp, NULL_TREE, 1); return; } - default: - /* For other expressions, simply recurse on their operands. - Manual tail recursion for unary expressions. - Other non-expressions need not be processed. */ - if (cl == tcc_unary) - { - x = TREE_OPERAND (x, 0); - writer = 0; - goto restart; - } - else if (IS_EXPR_CODE_CLASS (cl)) - { - int lp; - int max = TREE_CODE_LENGTH (TREE_CODE (x)); - for (lp = 0; lp < max; lp++) - { - tmp_before = tmp_nosp = 0; - verify_tree (TREE_OPERAND (x, lp), &tmp_before, &tmp_nosp, 0); - merge_tlist (&tmp_nosp, tmp_before, 0); - add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0); - } - } - return; + break; + } + + if (class == '1') + { + if (first_rtl_op (code) == 0) + return; + x = TREE_OPERAND (x, 0); + writer = 0; + goto restart; + } + + switch (class) + { + case 'r': + case '<': + case '2': + case 'b': + case 'e': + case 's': + case 'x': + { + int lp; + int max = first_rtl_op (TREE_CODE (x)); + for (lp = 0; lp < max; lp++) + { + tmp_before = tmp_nosp = 0; + verify_tree (TREE_OPERAND (x, lp), &tmp_before, &tmp_nosp, NULL_TREE); + merge_tlist (&tmp_nosp, tmp_before, 0); + add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0); + } + break; + } } } /* Try to warn for undefined behavior in EXPR due to missing sequence points. */ -void +static void verify_sequence_points (tree expr) { struct tlist *before_sp = 0, *after_sp = 0; @@ -1487,24 +1718,45 @@ verify_sequence_points (tree expr) if (tlist_firstobj == 0) { gcc_obstack_init (&tlist_obstack); - tlist_firstobj = (char *) obstack_alloc (&tlist_obstack, 0); + tlist_firstobj = obstack_alloc (&tlist_obstack, 0); } verify_tree (expr, &before_sp, &after_sp, 0); warn_for_collisions (after_sp); obstack_free (&tlist_obstack, tlist_firstobj); } + +tree +c_expand_expr_stmt (tree expr) +{ + /* Do default conversion if safe and possibly important, + in case within ({...}). */ + if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE + && (flag_isoc99 || lvalue_p (expr))) + || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE) + expr = default_conversion (expr); + + if (warn_sequence_point) + verify_sequence_points (expr); + + if (TREE_TYPE (expr) != error_mark_node + && !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr)) + && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE) + error ("expression statement has incomplete type"); + + last_expr_type = TREE_TYPE (expr); + return add_stmt (build_stmt (EXPR_STMT, expr)); +} /* Validate the expression after `case' and apply default promotions. */ -static tree +tree check_case_value (tree value) { if (value == NULL_TREE) return value; - /* ??? Can we ever get nops here for a valid case value? We - shouldn't for C. */ + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ STRIP_TYPE_NOPS (value); /* In C++, the following is allowed: @@ -1519,89 +1771,21 @@ check_case_value (tree value) value = fold (value); } - if (TREE_CODE (value) == INTEGER_CST) - /* Promote char or short to int. */ - value = perform_integral_promotions (value); - else if (value != error_mark_node) + if (TREE_CODE (value) != INTEGER_CST + && value != error_mark_node) { error ("case label does not reduce to an integer constant"); value = error_mark_node; } + else + /* Promote char or short to int. */ + value = default_conversion (value); constant_expression_warning (value); return value; } -/* See if the case values LOW and HIGH are in the range of the original - type (i.e. before the default conversion to int) of the switch testing - expression. - TYPE is the promoted type of the testing expression, and ORIG_TYPE is - the type before promoting it. CASE_LOW_P is a pointer to the lower - bound of the case label, and CASE_HIGH_P is the upper bound or NULL - if the case is not a case range. - The caller has to make sure that we are not called with NULL for - CASE_LOW_P (i.e. the default case). - Returns true if the case label is in range of ORIG_TYPE (saturated or - untouched) or false if the label is out of range. */ - -static bool -check_case_bounds (tree type, tree orig_type, - tree *case_low_p, tree *case_high_p) -{ - tree min_value, max_value; - tree case_low = *case_low_p; - tree case_high = case_high_p ? *case_high_p : case_low; - - /* If there was a problem with the original type, do nothing. */ - if (orig_type == error_mark_node) - return true; - - min_value = TYPE_MIN_VALUE (orig_type); - max_value = TYPE_MAX_VALUE (orig_type); - - /* Case label is less than minimum for type. */ - if (tree_int_cst_compare (case_low, min_value) < 0 - && tree_int_cst_compare (case_high, min_value) < 0) - { - warning (0, "case label value is less than minimum value for type"); - return false; - } - - /* Case value is greater than maximum for type. */ - if (tree_int_cst_compare (case_low, max_value) > 0 - && tree_int_cst_compare (case_high, max_value) > 0) - { - warning (0, "case label value exceeds maximum value for type"); - return false; - } - - /* Saturate lower case label value to minimum. */ - if (tree_int_cst_compare (case_high, min_value) >= 0 - && tree_int_cst_compare (case_low, min_value) < 0) - { - warning (0, "lower value in case label range" - " less than minimum value for type"); - case_low = min_value; - } - - /* Saturate upper case label value to maximum. */ - if (tree_int_cst_compare (case_low, max_value) <= 0 - && tree_int_cst_compare (case_high, max_value) > 0) - { - warning (0, "upper value in case label range" - " exceeds maximum value for type"); - case_high = max_value; - } - - if (*case_low_p != case_low) - *case_low_p = convert (type, case_low); - if (case_high_p && *case_high_p != case_high) - *case_high_p = convert (type, case_high); - - return true; -} - /* Return an integer type with BITS bits of precision, that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ @@ -1673,7 +1857,7 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp) if (mode == TYPE_MODE (widest_integer_literal_type_node)) return unsignedp ? widest_unsigned_literal_type_node - : widest_integer_literal_type_node; + : widest_integer_literal_type_node; if (mode == QImode) return unsignedp ? unsigned_intQI_type_node : intQI_type_node; @@ -1703,52 +1887,47 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp) if (mode == TYPE_MODE (void_type_node)) return void_type_node; - + if (mode == TYPE_MODE (build_pointer_type (char_type_node))) - return (unsignedp - ? make_unsigned_type (GET_MODE_PRECISION (mode)) - : make_signed_type (GET_MODE_PRECISION (mode))); + return unsignedp ? make_unsigned_type (mode) : make_signed_type (mode); if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) - return (unsignedp - ? make_unsigned_type (GET_MODE_PRECISION (mode)) - : make_signed_type (GET_MODE_PRECISION (mode))); - - if (COMPLEX_MODE_P (mode)) - { - enum machine_mode inner_mode; - tree inner_type; - - if (mode == TYPE_MODE (complex_float_type_node)) - return complex_float_type_node; - if (mode == TYPE_MODE (complex_double_type_node)) - return complex_double_type_node; - if (mode == TYPE_MODE (complex_long_double_type_node)) - return complex_long_double_type_node; - - if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp) - return complex_integer_type_node; - - inner_mode = GET_MODE_INNER (mode); - inner_type = c_common_type_for_mode (inner_mode, unsignedp); - if (inner_type != NULL_TREE) - return build_complex_type (inner_type); - } - else if (VECTOR_MODE_P (mode)) - { - enum machine_mode inner_mode = GET_MODE_INNER (mode); - tree inner_type = c_common_type_for_mode (inner_mode, unsignedp); - if (inner_type != NULL_TREE) - return build_vector_type_for_mode (inner_type, mode); + return unsignedp ? make_unsigned_type (mode) : make_signed_type (mode); + + switch (mode) + { + case V16QImode: + return unsignedp ? unsigned_V16QI_type_node : V16QI_type_node; + case V8HImode: + return unsignedp ? unsigned_V8HI_type_node : V8HI_type_node; + case V4SImode: + return unsignedp ? unsigned_V4SI_type_node : V4SI_type_node; + case V2DImode: + return unsignedp ? unsigned_V2DI_type_node : V2DI_type_node; + case V2SImode: + return unsignedp ? unsigned_V2SI_type_node : V2SI_type_node; + case V2HImode: + return unsignedp ? unsigned_V2HI_type_node : V2HI_type_node; + case V4HImode: + return unsignedp ? unsigned_V4HI_type_node : V4HI_type_node; + case V8QImode: + return unsignedp ? unsigned_V8QI_type_node : V8QI_type_node; + case V1DImode: + return unsignedp ? unsigned_V1DI_type_node : V1DI_type_node; + case V16SFmode: + return V16SF_type_node; + case V4SFmode: + return V4SF_type_node; + case V2SFmode: + return V2SF_type_node; + case V2DFmode: + return V2DF_type_node; + case V4DFmode: + return V4DF_type_node; + default: + break; } - if (mode == TYPE_MODE (dfloat32_type_node)) - return dfloat32_type_node; - if (mode == TYPE_MODE (dfloat64_type_node)) - return dfloat64_type_node; - if (mode == TYPE_MODE (dfloat128_type_node)) - return dfloat128_type_node; - for (t = registered_builtin_types; t; t = TREE_CHAIN (t)) if (TYPE_MODE (TREE_VALUE (t)) == mode) return TREE_VALUE (t); @@ -1829,80 +2008,44 @@ c_common_signed_type (tree type) tree c_common_signed_or_unsigned_type (int unsignedp, tree type) { - if (!INTEGRAL_TYPE_P (type) - || TYPE_UNSIGNED (type) == unsignedp) + if (! INTEGRAL_TYPE_P (type) + || TREE_UNSIGNED (type) == unsignedp) return type; - /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not - the precision; they have precision set to match their range, but - may use a wider mode to match an ABI. If we change modes, we may - wind up with bad conversions. For INTEGER_TYPEs in C, must check - the precision as well, so as to yield correct results for - bit-field types. C++ does not have these separate bit-field - types, and producing a signed or unsigned variant of an - ENUMERAL_TYPE may cause other problems as well. */ - -#define TYPE_OK(node) \ - (TYPE_MODE (type) == TYPE_MODE (node) \ - && (c_dialect_cxx () || TYPE_PRECISION (type) == TYPE_PRECISION (node))) - if (TYPE_OK (signed_char_type_node)) + /* Must check the mode of the types, not the precision. Enumeral types + in C++ have precision set to match their range, but may use a wider + mode to match an ABI. If we change modes, we may wind up with bad + conversions. */ + + if (TYPE_MODE (type) == TYPE_MODE (signed_char_type_node)) return unsignedp ? unsigned_char_type_node : signed_char_type_node; - if (TYPE_OK (integer_type_node)) + if (TYPE_MODE (type) == TYPE_MODE (integer_type_node)) return unsignedp ? unsigned_type_node : integer_type_node; - if (TYPE_OK (short_integer_type_node)) + if (TYPE_MODE (type) == TYPE_MODE (short_integer_type_node)) return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (TYPE_OK (long_integer_type_node)) + if (TYPE_MODE (type) == TYPE_MODE (long_integer_type_node)) return unsignedp ? long_unsigned_type_node : long_integer_type_node; - if (TYPE_OK (long_long_integer_type_node)) + if (TYPE_MODE (type) == TYPE_MODE (long_long_integer_type_node)) return (unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node); - if (TYPE_OK (widest_integer_literal_type_node)) + if (TYPE_MODE (type) == TYPE_MODE (widest_integer_literal_type_node)) return (unsignedp ? widest_unsigned_literal_type_node : widest_integer_literal_type_node); #if HOST_BITS_PER_WIDE_INT >= 64 - if (TYPE_OK (intTI_type_node)) + if (TYPE_MODE (type) == TYPE_MODE (intTI_type_node)) return unsignedp ? unsigned_intTI_type_node : intTI_type_node; #endif - if (TYPE_OK (intDI_type_node)) + if (TYPE_MODE (type) == TYPE_MODE (intDI_type_node)) return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - if (TYPE_OK (intSI_type_node)) + if (TYPE_MODE (type) == TYPE_MODE (intSI_type_node)) return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - if (TYPE_OK (intHI_type_node)) + if (TYPE_MODE (type) == TYPE_MODE (intHI_type_node)) return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - if (TYPE_OK (intQI_type_node)) + if (TYPE_MODE (type) == TYPE_MODE (intQI_type_node)) return unsignedp ? unsigned_intQI_type_node : intQI_type_node; -#undef TYPE_OK - if (c_dialect_cxx ()) - return type; - else - return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp); -} - -/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP. */ - -tree -c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp) -{ - /* Extended integer types of the same width as a standard type have - lesser rank, so those of the same width as int promote to int or - unsigned int and are valid for printf formats expecting int or - unsigned int. To avoid such special cases, avoid creating - extended integer types for bit-fields if a standard integer type - is available. */ - if (width == TYPE_PRECISION (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - if (width == TYPE_PRECISION (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - if (width == TYPE_PRECISION (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (width == TYPE_PRECISION (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - if (width == TYPE_PRECISION (long_long_integer_type_node)) - return (unsignedp ? long_long_unsigned_type_node - : long_long_integer_type_node); - return build_nonstandard_integer_type (width, unsignedp); + return type; } /* The C version of the register_builtin_type langhook. */ @@ -1936,7 +2079,7 @@ min_precision (tree value, int unsignedp) a bit-wise negation, so use that operation instead. */ if (tree_int_cst_sgn (value) < 0) - value = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (value), value); + value = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (value), value)); /* Return the number of bits needed, taking into account the fact that we need one more bit for a signed than unsigned type. */ @@ -1946,11 +2089,12 @@ min_precision (tree value, int unsignedp) else log = tree_floor_log2 (value); - return log + 1 + !unsignedp; + return log + 1 + ! unsignedp; } /* Print an error message for invalid operands to arith operation - CODE. */ + CODE. NOP_EXPR is used as a special case (see + c_common_truthvalue_conversion). */ void binary_op_error (enum tree_code code) @@ -1959,6 +2103,10 @@ binary_op_error (enum tree_code code) switch (code) { + case NOP_EXPR: + error ("invalid truth-value expression"); + return; + case PLUS_EXPR: opname = "+"; break; case MINUS_EXPR: @@ -2001,8 +2149,11 @@ binary_op_error (enum tree_code code) opname = "||"; break; case BIT_XOR_EXPR: opname = "^"; break; + case LROTATE_EXPR: + case RROTATE_EXPR: + opname = "rotate"; break; default: - gcc_unreachable (); + opname = "unknown"; break; } error ("invalid operands to binary %s", opname); } @@ -2043,9 +2194,9 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, but it *requires* conversion to FINAL_TYPE. */ if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr) - unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (op0)); + unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0)); if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr) - unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (op1)); + unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1)); /* If one of the operands must be floated, we cannot optimize. */ real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE; @@ -2056,7 +2207,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, the second arg is 0. */ if (TREE_CONSTANT (primop0) - && !integer_zerop (primop1) && !real_zerop (primop1)) + && ! integer_zerop (primop1) && ! real_zerop (primop1)) { tree tem = primop0; int temi = unsignedp0; @@ -2117,12 +2268,20 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, int min_gt, max_gt, min_lt, max_lt; tree maxval, minval; /* 1 if comparison is nominally unsigned. */ - int unsignedp = TYPE_UNSIGNED (*restype_ptr); + int unsignedp = TREE_UNSIGNED (*restype_ptr); tree val; type = c_common_signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)); + /* In C, if TYPE is an enumeration, then we need to get its + min/max values from it's underlying integral type, not the + enumerated type itself. In C++, TYPE_MAX_VALUE and + TYPE_MIN_VALUE have already been set correctly on the + enumeration type. */ + if (!c_dialect_cxx() && TREE_CODE (type) == ENUMERAL_TYPE) + type = c_common_type_for_size (TYPE_PRECISION (type), unsignedp0); + maxval = TYPE_MAX_VALUE (type); minval = TYPE_MIN_VALUE (type); @@ -2130,16 +2289,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, *restype_ptr = c_common_signed_type (*restype_ptr); if (TREE_TYPE (primop1) != *restype_ptr) - { - /* Convert primop1 to target type, but do not introduce - additional overflow. We know primop1 is an int_cst. */ - tree tmp = build_int_cst_wide (*restype_ptr, - TREE_INT_CST_LOW (primop1), - TREE_INT_CST_HIGH (primop1)); - - primop1 = force_fit_type (tmp, 0, TREE_OVERFLOW (primop1), - TREE_CONSTANT_OVERFLOW (primop1)); - } + primop1 = convert (*restype_ptr, primop1); if (type != *restype_ptr) { minval = convert (*restype_ptr, minval); @@ -2239,16 +2389,16 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, if (TREE_CODE (primop0) != INTEGER_CST) { if (val == truthvalue_false_node) - warning (0, "comparison is always false due to limited range of data type"); + warning ("comparison is always false due to limited range of data type"); if (val == truthvalue_true_node) - warning (0, "comparison is always true due to limited range of data type"); + warning ("comparison is always true due to limited range of data type"); } if (val != 0) { /* Don't forget to evaluate PRIMOP0 if it has side effects. */ if (TREE_SIDE_EFFECTS (primop0)) - return build2 (COMPOUND_EXPR, TREE_TYPE (val), primop0, val); + return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val); return val; } @@ -2256,14 +2406,6 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, in the type of the operand that is not constant. TYPE is already properly set. */ } - - /* If either arg is decimal float and the other is float, find the - proper common type to use for comparison. */ - else if (real1 && real2 - && (DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (primop0))) - || DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (primop1))))) - type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)); - else if (real1 && real2 && (TYPE_PRECISION (TREE_TYPE (primop0)) == TYPE_PRECISION (TREE_TYPE (primop1)))) @@ -2283,7 +2425,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, { type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)); type = c_common_signed_or_unsigned_type (unsignedp0 - || TYPE_UNSIGNED (*restype_ptr), + || TREE_UNSIGNED (*restype_ptr), type); /* Make sure shorter operand is extended the right way to match the longer operand. */ @@ -2305,7 +2447,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, primop1 = op1; if (!real1 && !real2 && integer_zerop (primop1) - && TYPE_UNSIGNED (*restype_ptr)) + && TREE_UNSIGNED (*restype_ptr)) { tree value = 0; switch (code) @@ -2316,19 +2458,19 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, >= 0, the signedness of the comparison isn't an issue, so suppress the warning. */ if (extra_warnings && !in_system_header - && !(TREE_CODE (primop0) == INTEGER_CST - && !TREE_OVERFLOW (convert (c_common_signed_type (type), - primop0)))) - warning (0, "comparison of unsigned expression >= 0 is always true"); + && ! (TREE_CODE (primop0) == INTEGER_CST + && ! TREE_OVERFLOW (convert (c_common_signed_type (type), + primop0)))) + warning ("comparison of unsigned expression >= 0 is always true"); value = truthvalue_true_node; break; case LT_EXPR: if (extra_warnings && !in_system_header - && !(TREE_CODE (primop0) == INTEGER_CST - && !TREE_OVERFLOW (convert (c_common_signed_type (type), - primop0)))) - warning (0, "comparison of unsigned expression < 0 is always false"); + && ! (TREE_CODE (primop0) == INTEGER_CST + && ! TREE_OVERFLOW (convert (c_common_signed_type (type), + primop0)))) + warning ("comparison of unsigned expression < 0 is always false"); value = truthvalue_false_node; break; @@ -2340,8 +2482,8 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, { /* Don't forget to evaluate PRIMOP0 if it has side effects. */ if (TREE_SIDE_EFFECTS (primop0)) - return build2 (COMPOUND_EXPR, TREE_TYPE (value), - primop0, value); + return build (COMPOUND_EXPR, TREE_TYPE (value), + primop0, value); return value; } } @@ -2361,7 +2503,10 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, tree pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) { - tree size_exp, ret; + tree size_exp; + + tree result; + tree folded; /* The result is a pointer of the same type that is being added. */ @@ -2370,7 +2515,7 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) { if (pedantic || warn_pointer_arith) - pedwarn ("pointer of type %<void *%> used in arithmetic"); + pedwarn ("pointer of type `void *' used in arithmetic"); size_exp = integer_one_node; } else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE) @@ -2388,19 +2533,13 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) else size_exp = size_in_bytes (TREE_TYPE (result_type)); - /* We are manipulating pointer values, so we don't need to warn - about relying on undefined signed overflow. We disable the - warning here because we use integer types so fold won't know that - they are really pointers. */ - fold_defer_overflow_warnings (); - /* If what we are about to multiply by the size of the elements contains a constant term, apply distributive law and multiply that constant term separately. This helps produce common subexpressions. */ if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR) - && !TREE_CONSTANT (intop) + && ! TREE_CONSTANT (intop) && TREE_CONSTANT (TREE_OPERAND (intop, 1)) && TREE_CONSTANT (size_exp) /* If the constant comes from pointer subtraction, @@ -2409,7 +2548,7 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) /* If the constant is unsigned, and smaller than the pointer size, then we must skip this optimization. This is because it could cause an overflow error if the constant is negative but INTOP is not. */ - && (!TYPE_UNSIGNED (TREE_TYPE (intop)) + && (! TREE_UNSIGNED (TREE_TYPE (intop)) || (TYPE_PRECISION (TREE_TYPE (intop)) == TYPE_PRECISION (TREE_TYPE (ptrop))))) { @@ -2429,9 +2568,9 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) so the multiply won't overflow spuriously. */ if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype) - || TYPE_UNSIGNED (TREE_TYPE (intop)) != TYPE_UNSIGNED (sizetype)) + || TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype)) intop = convert (c_common_type_for_size (TYPE_PRECISION (sizetype), - TYPE_UNSIGNED (sizetype)), intop); + TREE_UNSIGNED (sizetype)), intop); /* Replace the integer argument with a suitable product by the object size. Do this multiplication as signed, then convert to the appropriate @@ -2442,17 +2581,17 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) convert (TREE_TYPE (intop), size_exp), 1)); /* Create the sum or difference. */ - ret = fold_build2 (resultcode, result_type, ptrop, intop); - fold_undefer_and_ignore_overflow_warnings (); + result = build (resultcode, result_type, ptrop, intop); - return ret; + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop); + return folded; } /* Prepare expr to be an argument of a TRUTH_NOT_EXPR, - or for an `if' or `while' statement or ?..: exp. It should already - have been validated to be of suitable type; otherwise, a bad - diagnostic may result. + or validate its data type for an `if' or `while' statement or ?..: exp. This preparation consists of taking the ordinary representation of an expression expr and producing a valid tree @@ -2465,77 +2604,77 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) tree c_common_truthvalue_conversion (tree expr) { - switch (TREE_CODE (expr)) + if (TREE_CODE (expr) == ERROR_MARK) + return expr; + + if (TREE_CODE (expr) == FUNCTION_DECL) + expr = build_unary_op (ADDR_EXPR, expr, 0); + +#if 0 /* This appears to be wrong for C++. */ + /* These really should return error_mark_node after 2.4 is stable. + But not all callers handle ERROR_MARK properly. */ + switch (TREE_CODE (TREE_TYPE (expr))) { - case EQ_EXPR: case NE_EXPR: case UNEQ_EXPR: case LTGT_EXPR: - case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: - case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR: - case ORDERED_EXPR: case UNORDERED_EXPR: - if (TREE_TYPE (expr) == truthvalue_type_node) - return expr; - return build2 (TREE_CODE (expr), truthvalue_type_node, - TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1)); + case RECORD_TYPE: + error ("struct type value used where scalar is required"); + return truthvalue_false_node; + + case UNION_TYPE: + error ("union type value used where scalar is required"); + return truthvalue_false_node; + + case ARRAY_TYPE: + error ("array type value used where scalar is required"); + return truthvalue_false_node; + + default: + break; + } +#endif /* 0 */ + switch (TREE_CODE (expr)) + { + case EQ_EXPR: + case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case TRUTH_XOR_EXPR: - if (TREE_TYPE (expr) == truthvalue_type_node) - return expr; - return build2 (TREE_CODE (expr), truthvalue_type_node, - c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)), - c_common_truthvalue_conversion (TREE_OPERAND (expr, 1))); - case TRUTH_NOT_EXPR: - if (TREE_TYPE (expr) == truthvalue_type_node) - return expr; - return build1 (TREE_CODE (expr), truthvalue_type_node, - c_common_truthvalue_conversion (TREE_OPERAND (expr, 0))); + TREE_TYPE (expr) = truthvalue_type_node; + return expr; case ERROR_MARK: return expr; case INTEGER_CST: - /* Avoid integer_zerop to ignore TREE_CONSTANT_OVERFLOW. */ - return (TREE_INT_CST_LOW (expr) != 0 || TREE_INT_CST_HIGH (expr) != 0) - ? truthvalue_true_node - : truthvalue_false_node; + return integer_zerop (expr) ? truthvalue_false_node : truthvalue_true_node; case REAL_CST: - return real_compare (NE_EXPR, &TREE_REAL_CST (expr), &dconst0) - ? truthvalue_true_node - : truthvalue_false_node; - - case FUNCTION_DECL: - expr = build_unary_op (ADDR_EXPR, expr, 0); - /* Fall through. */ + return real_zerop (expr) ? truthvalue_false_node : truthvalue_true_node; case ADDR_EXPR: { - tree inner = TREE_OPERAND (expr, 0); - if (DECL_P (inner) - && (TREE_CODE (inner) == PARM_DECL - || TREE_CODE (inner) == LABEL_DECL - || !DECL_WEAK (inner))) + if (TREE_CODE (TREE_OPERAND (expr, 0)) == FUNCTION_DECL + && ! DECL_WEAK (TREE_OPERAND (expr, 0))) { - /* Common Ada/Pascal programmer's mistake. We always warn + /* Common Ada/Pascal programmer's mistake. We always warn about this since it is so bad. */ - warning (OPT_Waddress, - "the address of %qD will always evaluate as %<true%>", - inner); + warning ("the address of `%D', will always evaluate as `true'", + TREE_OPERAND (expr, 0)); return truthvalue_true_node; } /* If we are taking the address of an external decl, it might be zero if it is weak, so we cannot optimize. */ - if (DECL_P (inner) - && DECL_EXTERNAL (inner)) + if (DECL_P (TREE_OPERAND (expr, 0)) + && DECL_EXTERNAL (TREE_OPERAND (expr, 0))) break; - if (TREE_SIDE_EFFECTS (inner)) - return build2 (COMPOUND_EXPR, truthvalue_type_node, - inner, truthvalue_true_node); + if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0))) + return build (COMPOUND_EXPR, truthvalue_type_node, + TREE_OPERAND (expr, 0), truthvalue_true_node); else return truthvalue_true_node; } @@ -2558,36 +2697,65 @@ c_common_truthvalue_conversion (tree expr) /* These don't change whether an object is zero or nonzero, but we can't ignore them if their second arg has side-effects. */ if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))) - return build2 (COMPOUND_EXPR, truthvalue_type_node, - TREE_OPERAND (expr, 1), - c_common_truthvalue_conversion (TREE_OPERAND (expr, 0))); + return build (COMPOUND_EXPR, truthvalue_type_node, TREE_OPERAND (expr, 1), + c_common_truthvalue_conversion (TREE_OPERAND (expr, 0))); else return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)); case COND_EXPR: /* Distribute the conversion into the arms of a COND_EXPR. */ - return fold_build3 (COND_EXPR, truthvalue_type_node, - TREE_OPERAND (expr, 0), + return fold (build (COND_EXPR, truthvalue_type_node, TREE_OPERAND (expr, 0), c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)), - c_common_truthvalue_conversion (TREE_OPERAND (expr, 2))); + c_common_truthvalue_conversion (TREE_OPERAND (expr, 2)))); case CONVERT_EXPR: - case NOP_EXPR: /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE, since that affects how `default_conversion' will behave. */ if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE) break; + /* Fall through.... */ + case NOP_EXPR: /* If this is widening the argument, we can ignore it. */ if (TYPE_PRECISION (TREE_TYPE (expr)) >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)); break; + case MINUS_EXPR: + /* Perhaps reduce (x - y) != 0 to (x != y). The expressions + aren't guaranteed to the be same for modes that can represent + infinity, since if x and y are both +infinity, or both + -infinity, then x - y is not a number. + + Note that this transformation is safe when x or y is NaN. + (x - y) is then NaN, and both (x - y) != 0 and x != y will + be false. */ + if (HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (TREE_OPERAND (expr, 0))))) + break; + /* Fall through.... */ + case BIT_XOR_EXPR: + /* This and MINUS_EXPR can be changed into a comparison of the + two objects. */ + if (TREE_TYPE (TREE_OPERAND (expr, 0)) + == TREE_TYPE (TREE_OPERAND (expr, 1))) + return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0), + TREE_OPERAND (expr, 1), 1); + return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0), + fold (build1 (NOP_EXPR, + TREE_TYPE (TREE_OPERAND (expr, 0)), + TREE_OPERAND (expr, 1))), 1); + + case BIT_AND_EXPR: + if (integer_onep (TREE_OPERAND (expr, 1)) + && TREE_TYPE (expr) != truthvalue_type_node) + /* Using convert here would cause infinite recursion. */ + return build1 (NOP_EXPR, truthvalue_type_node, expr); + break; + case MODIFY_EXPR: - if (!TREE_NO_WARNING (expr)) - warning (OPT_Wparentheses, - "suggest parentheses around assignment used as truth value"); + if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR) + warning ("suggest parentheses around assignment used as truth value"); break; default: @@ -2608,12 +2776,9 @@ c_common_truthvalue_conversion (tree expr) return build_binary_op (NE_EXPR, expr, integer_zero_node, 1); } -static void def_builtin_1 (enum built_in_function fncode, - const char *name, - enum built_in_class fnclass, - tree fntype, tree libtype, - bool both_p, bool fallback_p, bool nonansi_p, - tree fnattrs, bool implicit_p); +static tree builtin_function_2 (const char *, const char *, tree, tree, + int, enum built_in_class, int, int, + tree); /* Make a variant type in the proper way for C/C++, propagating qualifiers down to the element type of an array. */ @@ -2623,30 +2788,11 @@ c_build_qualified_type (tree type, int type_quals) { if (type == error_mark_node) return type; - + if (TREE_CODE (type) == ARRAY_TYPE) - { - tree t; - tree element_type = c_build_qualified_type (TREE_TYPE (type), - type_quals); - - /* See if we already have an identically qualified type. */ - for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) - { - if (TYPE_QUALS (strip_array_types (t)) == type_quals - && TYPE_NAME (t) == TYPE_NAME (type) - && TYPE_CONTEXT (t) == TYPE_CONTEXT (type) - && attribute_list_equal (TYPE_ATTRIBUTES (t), - TYPE_ATTRIBUTES (type))) - break; - } - if (!t) - { - t = build_variant_type_copy (type); - TREE_TYPE (t) = element_type; - } - return t; - } + return build_array_type (c_build_qualified_type (TREE_TYPE (type), + type_quals), + TYPE_DOMAIN (type)); /* A restrict-qualified pointer type must be a pointer to object or incomplete type. Note that the use of POINTER_TYPE_P also allows @@ -2655,7 +2801,7 @@ c_build_qualified_type (tree type, int type_quals) && (!POINTER_TYPE_P (type) || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))) { - error ("invalid use of %<restrict%>"); + error ("invalid use of `restrict'"); type_quals &= ~TYPE_QUAL_RESTRICT; } @@ -2668,7 +2814,7 @@ void c_apply_type_quals_to_decl (int type_quals, tree decl) { tree type = TREE_TYPE (decl); - + if (type == error_mark_node) return; @@ -2695,7 +2841,7 @@ c_apply_type_quals_to_decl (int type_quals, tree decl) if (!type || !POINTER_TYPE_P (type) || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type))) - error ("invalid use of %<restrict%>"); + error ("invalid use of `restrict'"); else if (flag_strict_aliasing && type == TREE_TYPE (decl)) /* Indicate we need to make a unique alias set for this pointer. We can't do it here because it might be pointing to an @@ -2704,51 +2850,6 @@ c_apply_type_quals_to_decl (int type_quals, tree decl) } } -/* Hash function for the problem of multiple type definitions in - different files. This must hash all types that will compare - equal via comptypes to the same value. In practice it hashes - on some of the simple stuff and leaves the details to comptypes. */ - -static hashval_t -c_type_hash (const void *p) -{ - int i = 0; - int shift, size; - tree t = (tree) p; - tree t2; - switch (TREE_CODE (t)) - { - /* For pointers, hash on pointee type plus some swizzling. */ - case POINTER_TYPE: - return c_type_hash (TREE_TYPE (t)) ^ 0x3003003; - /* Hash on number of elements and total size. */ - case ENUMERAL_TYPE: - shift = 3; - t2 = TYPE_VALUES (t); - break; - case RECORD_TYPE: - shift = 0; - t2 = TYPE_FIELDS (t); - break; - case QUAL_UNION_TYPE: - shift = 1; - t2 = TYPE_FIELDS (t); - break; - case UNION_TYPE: - shift = 2; - t2 = TYPE_FIELDS (t); - break; - default: - gcc_unreachable (); - } - for (; t2; t2 = TREE_CHAIN (t2)) - i++; - size = TREE_INT_CST_LOW (TYPE_SIZE (t)); - return ((size << 24) | (i << shift)); -} - -static GTY((param_is (union tree_node))) htab_t type_hash_table; - /* Return the typed-based alias set for T, which may be an expression or a type. Return -1 if we don't do anything special. */ @@ -2756,7 +2857,6 @@ HOST_WIDE_INT c_common_get_alias_set (tree t) { tree u; - PTR *slot; /* Permit type-punning when accessing a union, provided the access is directly through the union. For example, this code does not @@ -2772,7 +2872,7 @@ c_common_get_alias_set (tree t) return 0; /* That's all the expressions we handle specially. */ - if (!TYPE_P (t)) + if (! TYPE_P (t)) return -1; /* The C standard guarantees that any object may be accessed via an @@ -2789,7 +2889,7 @@ c_common_get_alias_set (tree t) /* The C standard specifically allows aliasing between signed and unsigned variants of the same type. We treat the signed variant as canonical. */ - if (TREE_CODE (t) == INTEGER_TYPE && TYPE_UNSIGNED (t)) + if (TREE_CODE (t) == INTEGER_TYPE && TREE_UNSIGNED (t)) { tree t1 = c_common_signed_type (t); @@ -2813,14 +2913,14 @@ c_common_get_alias_set (tree t) technically, an `int **' and `const int **' cannot point at the same thing. - But, the standard is wrong. In particular, this code is + But, the standard is wrong. In particular, this code is legal C++: - int *ip; - int **ipp = &ip; - const int* const* cipp = ipp; + int *ip; + int **ipp = &ip; + const int* const* cipp = &ipp; - And, it doesn't make sense for that to be legal unless you + And, it doesn't make sense for that to be legal unless you can dereference IPP and CIPP. So, we ignore cv-qualifiers on the pointed-to types. This issue has been reported to the C++ committee. */ @@ -2829,66 +2929,6 @@ c_common_get_alias_set (tree t) return get_alias_set (t1); } - /* Handle the case of multiple type nodes referring to "the same" type, - which occurs with IMA. These share an alias set. FIXME: Currently only - C90 is handled. (In C99 type compatibility is not transitive, which - complicates things mightily. The alias set splay trees can theoretically - represent this, but insertion is tricky when you consider all the - different orders things might arrive in.) */ - - if (c_language != clk_c || flag_isoc99) - return -1; - - /* Save time if there's only one input file. */ - if (num_in_fnames == 1) - return -1; - - /* Pointers need special handling if they point to any type that - needs special handling (below). */ - if (TREE_CODE (t) == POINTER_TYPE) - { - tree t2; - /* Find bottom type under any nested POINTERs. */ - for (t2 = TREE_TYPE (t); - TREE_CODE (t2) == POINTER_TYPE; - t2 = TREE_TYPE (t2)) - ; - if (TREE_CODE (t2) != RECORD_TYPE - && TREE_CODE (t2) != ENUMERAL_TYPE - && TREE_CODE (t2) != QUAL_UNION_TYPE - && TREE_CODE (t2) != UNION_TYPE) - return -1; - if (TYPE_SIZE (t2) == 0) - return -1; - } - /* These are the only cases that need special handling. */ - if (TREE_CODE (t) != RECORD_TYPE - && TREE_CODE (t) != ENUMERAL_TYPE - && TREE_CODE (t) != QUAL_UNION_TYPE - && TREE_CODE (t) != UNION_TYPE - && TREE_CODE (t) != POINTER_TYPE) - return -1; - /* Undefined? */ - if (TYPE_SIZE (t) == 0) - return -1; - - /* Look up t in hash table. Only one of the compatible types within each - alias set is recorded in the table. */ - if (!type_hash_table) - type_hash_table = htab_create_ggc (1021, c_type_hash, - (htab_eq) lang_hooks.types_compatible_p, - NULL); - slot = htab_find_slot (type_hash_table, t, INSERT); - if (*slot != NULL) - { - TYPE_ALIAS_SET (t) = TYPE_ALIAS_SET ((tree)*slot); - return TYPE_ALIAS_SET ((tree)*slot); - } - else - /* Our caller will assign and record (in t) a new alias set; all we need - to do is remember t in the hash table. */ - *slot = t; - return -1; } @@ -2896,22 +2936,22 @@ c_common_get_alias_set (tree t) second parameter indicates which OPERATOR is being applied. The COMPLAIN flag controls whether we should diagnose possibly ill-formed constructs or not. */ - tree -c_sizeof_or_alignof_type (tree type, bool is_sizeof, int complain) +c_sizeof_or_alignof_type (tree type, enum tree_code op, int complain) { const char *op_name; tree value = NULL; enum tree_code type_code = TREE_CODE (type); - op_name = is_sizeof ? "sizeof" : "__alignof__"; + my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720); + op_name = op == SIZEOF_EXPR ? "sizeof" : "__alignof__"; if (type_code == FUNCTION_TYPE) { - if (is_sizeof) + if (op == SIZEOF_EXPR) { if (complain && (pedantic || warn_pointer_arith)) - pedwarn ("invalid application of %<sizeof%> to a function type"); + pedwarn ("invalid application of `sizeof' to a function type"); value = size_one_node; } else @@ -2921,33 +2961,33 @@ c_sizeof_or_alignof_type (tree type, bool is_sizeof, int complain) { if (type_code == VOID_TYPE && complain && (pedantic || warn_pointer_arith)) - pedwarn ("invalid application of %qs to a void type", op_name); + pedwarn ("invalid application of `%s' to a void type", op_name); value = size_one_node; } else if (!COMPLETE_TYPE_P (type)) { if (complain) - error ("invalid application of %qs to incomplete type %qT ", + error ("invalid application of `%s' to incomplete type `%T' ", op_name, type); value = size_zero_node; } else { - if (is_sizeof) + if (op == SIZEOF_EXPR) /* Convert in case a char is more than one unit. */ value = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type), size_int (TYPE_PRECISION (char_type_node) / BITS_PER_UNIT)); else - value = size_int (TYPE_ALIGN_UNIT (type)); + value = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT); } /* VALUE will have an integer type with TYPE_IS_SIZETYPE set. TYPE_IS_SIZETYPE means that certain things (like overflow) will never happen. However, this node should really have type `size_t', which is just a typedef for an ordinary integer type. */ - value = fold_convert (size_type_node, value); - gcc_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value))); + value = fold (build1 (NOP_EXPR, size_type_node, value)); + my_friendly_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value)), 20001021); return value; } @@ -2963,17 +3003,17 @@ c_alignof_expr (tree expr) tree t; if (TREE_CODE (expr) == VAR_DECL) - t = size_int (DECL_ALIGN_UNIT (expr)); + t = size_int (DECL_ALIGN (expr) / BITS_PER_UNIT); else if (TREE_CODE (expr) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1))) { - error ("%<__alignof%> applied to a bit-field"); + error ("`__alignof' applied to a bit-field"); t = size_one_node; } else if (TREE_CODE (expr) == COMPONENT_REF && TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL) - t = size_int (DECL_ALIGN_UNIT (TREE_OPERAND (expr, 1))); + t = size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT); else if (TREE_CODE (expr) == INDIRECT_REF) { @@ -2981,7 +3021,7 @@ c_alignof_expr (tree expr) tree best = t; int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); - while ((TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR) + while (TREE_CODE (t) == NOP_EXPR && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE) { int thisalign; @@ -2996,7 +3036,7 @@ c_alignof_expr (tree expr) else return c_alignof (TREE_TYPE (expr)); - return fold_convert (size_type_node, t); + return fold (build1 (NOP_EXPR, size_type_node, t)); } /* Handle C and C++ default attributes. */ @@ -3019,24 +3059,24 @@ static GTY(()) tree built_in_attributes[(int) ATTR_LAST]; static void c_init_attributes (void); -enum c_builtin_type +/* Build tree nodes and builtin functions common to both C and C++ language + frontends. */ + +void +c_common_nodes_and_builtins (void) { + enum builtin_type + { #define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME, #define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME, #define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, #define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, -#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, -#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, -#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, #define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, -#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, -#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \ - NAME, #define DEF_POINTER_TYPE(NAME, TYPE) NAME, #include "builtin-types.def" #undef DEF_PRIMITIVE_TYPE @@ -3045,71 +3085,17 @@ enum c_builtin_type #undef DEF_FUNCTION_TYPE_2 #undef DEF_FUNCTION_TYPE_3 #undef DEF_FUNCTION_TYPE_4 -#undef DEF_FUNCTION_TYPE_5 -#undef DEF_FUNCTION_TYPE_6 -#undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 #undef DEF_FUNCTION_TYPE_VAR_3 -#undef DEF_FUNCTION_TYPE_VAR_4 -#undef DEF_FUNCTION_TYPE_VAR_5 #undef DEF_POINTER_TYPE - BT_LAST -}; - -typedef enum c_builtin_type builtin_type; - -/* A temporary array for c_common_nodes_and_builtins. Used in - communication with def_fn_type. */ -static tree builtin_types[(int) BT_LAST + 1]; + BT_LAST + }; -/* A helper function for c_common_nodes_and_builtins. Build function type - for DEF with return type RET and N arguments. If VAR is true, then the - function should be variadic after those N arguments. + typedef enum builtin_type builtin_type; - Takes special care not to ICE if any of the types involved are - error_mark_node, which indicates that said type is not in fact available - (see builtin_type_for_size). In which case the function type as a whole - should be error_mark_node. */ - -static void -def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...) -{ - tree args = NULL, t; - va_list list; - int i; - - va_start (list, n); - for (i = 0; i < n; ++i) - { - builtin_type a = va_arg (list, builtin_type); - t = builtin_types[a]; - if (t == error_mark_node) - goto egress; - args = tree_cons (NULL_TREE, t, args); - } - va_end (list); - - args = nreverse (args); - if (!var) - args = chainon (args, void_list_node); - - t = builtin_types[ret]; - if (t == error_mark_node) - goto egress; - t = build_function_type (t, args); - - egress: - builtin_types[def] = t; -} - -/* Build tree nodes and builtin functions common to both C and C++ language - frontends. */ - -void -c_common_nodes_and_builtins (void) -{ + tree builtin_types[(int) BT_LAST]; int wchar_type_size; tree array_domain_type; tree va_list_ref_type_node; @@ -3150,45 +3136,43 @@ c_common_nodes_and_builtins (void) /* These are types that c_common_type_for_size and c_common_type_for_mode use. */ - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE, - intQI_type_node)); - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE, - intHI_type_node)); - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE, - intSI_type_node)); - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE, - intDI_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE, + intQI_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE, + intHI_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE, + intSI_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE, + intDI_type_node)); #if HOST_BITS_PER_WIDE_INT >= 64 - if (targetm.scalar_mode_supported_p (TImode)) - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, - get_identifier ("__int128_t"), - intTI_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, + get_identifier ("__int128_t"), + intTI_type_node)); #endif - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE, - unsigned_intQI_type_node)); - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE, - unsigned_intHI_type_node)); - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE, - unsigned_intSI_type_node)); - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE, - unsigned_intDI_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE, + unsigned_intQI_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE, + unsigned_intHI_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE, + unsigned_intSI_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE, + unsigned_intDI_type_node)); #if HOST_BITS_PER_WIDE_INT >= 64 - if (targetm.scalar_mode_supported_p (TImode)) - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, - get_identifier ("__uint128_t"), - unsigned_intTI_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, + get_identifier ("__uint128_t"), + unsigned_intTI_type_node)); #endif /* Create the widest literal types. */ widest_integer_literal_type_node = make_signed_type (HOST_BITS_PER_WIDE_INT * 2); - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE, - widest_integer_literal_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE, + widest_integer_literal_type_node)); widest_unsigned_literal_type_node = make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2); - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE, - widest_unsigned_literal_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE, + widest_unsigned_literal_type_node)); /* `unsigned long' is the standard type for sizeof. Note that stddef.h uses `unsigned long', @@ -3198,48 +3182,81 @@ c_common_nodes_and_builtins (void) signed_size_type_node = c_common_signed_type (size_type_node); set_sizetype (size_type_node); - pid_type_node = - TREE_TYPE (identifier_global_value (get_identifier (PID_TYPE))); - build_common_tree_nodes_2 (flag_short_double); record_builtin_type (RID_FLOAT, NULL, float_type_node); record_builtin_type (RID_DOUBLE, NULL, double_type_node); record_builtin_type (RID_MAX, "long double", long_double_type_node); - /* Only supported decimal floating point extension if the target - actually supports underlying modes. */ - if (targetm.scalar_mode_supported_p (SDmode) - && targetm.scalar_mode_supported_p (DDmode) - && targetm.scalar_mode_supported_p (TDmode)) - { - record_builtin_type (RID_DFLOAT32, NULL, dfloat32_type_node); - record_builtin_type (RID_DFLOAT64, NULL, dfloat64_type_node); - record_builtin_type (RID_DFLOAT128, NULL, dfloat128_type_node); - } - - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, - get_identifier ("complex int"), - complex_integer_type_node)); - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, - get_identifier ("complex float"), - complex_float_type_node)); - lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, - get_identifier ("complex double"), - complex_double_type_node)); - lang_hooks.decls.pushdecl + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, + get_identifier ("complex int"), + complex_integer_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, + get_identifier ("complex float"), + complex_float_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, + get_identifier ("complex double"), + complex_double_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, get_identifier ("complex long double"), complex_long_double_type_node)); - if (c_dialect_cxx ()) - /* For C++, make fileptr_type_node a distinct void * type until - FILE type is defined. */ - fileptr_type_node = build_variant_type_copy (ptr_type_node); + /* Types which are common to the fortran compiler and libf2c. When + changing these, you also need to be concerned with f/com.h. */ + + if (TYPE_PRECISION (float_type_node) + == TYPE_PRECISION (long_integer_type_node)) + { + g77_integer_type_node = long_integer_type_node; + g77_uinteger_type_node = long_unsigned_type_node; + } + else if (TYPE_PRECISION (float_type_node) + == TYPE_PRECISION (integer_type_node)) + { + g77_integer_type_node = integer_type_node; + g77_uinteger_type_node = unsigned_type_node; + } + else + g77_integer_type_node = g77_uinteger_type_node = NULL_TREE; + + if (g77_integer_type_node != NULL_TREE) + { + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, + get_identifier ("__g77_integer"), + g77_integer_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, + get_identifier ("__g77_uinteger"), + g77_uinteger_type_node)); + } + + if (TYPE_PRECISION (float_type_node) * 2 + == TYPE_PRECISION (long_integer_type_node)) + { + g77_longint_type_node = long_integer_type_node; + g77_ulongint_type_node = long_unsigned_type_node; + } + else if (TYPE_PRECISION (float_type_node) * 2 + == TYPE_PRECISION (long_long_integer_type_node)) + { + g77_longint_type_node = long_long_integer_type_node; + g77_ulongint_type_node = long_long_unsigned_type_node; + } + else + g77_longint_type_node = g77_ulongint_type_node = NULL_TREE; + + if (g77_longint_type_node != NULL_TREE) + { + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, + get_identifier ("__g77_longint"), + g77_longint_type_node)); + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, + get_identifier ("__g77_ulongint"), + g77_ulongint_type_node)); + } record_builtin_type (RID_VOID, NULL, void_type_node); - /* This node must not be shared. */ - void_zero_node = make_node (INTEGER_CST); + void_zero_node = build_int_2 (0, 0); TREE_TYPE (void_zero_node) = void_type_node; void_list_node = build_void_list_node (); @@ -3272,7 +3289,7 @@ c_common_nodes_and_builtins (void) wchar_type_size = TYPE_PRECISION (wchar_type_node); if (c_dialect_cxx ()) { - if (TYPE_UNSIGNED (wchar_type_node)) + if (TREE_UNSIGNED (wchar_type_node)) wchar_type_node = make_unsigned_type (wchar_type_size); else wchar_type_node = make_signed_type (wchar_type_size); @@ -3301,10 +3318,18 @@ c_common_nodes_and_builtins (void) = TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE))); unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node); - lang_hooks.decls.pushdecl + (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, get_identifier ("__builtin_va_list"), va_list_type_node)); + (*lang_hooks.decls.pushdecl) + (build_decl (TYPE_DECL, get_identifier ("__builtin_ptrdiff_t"), + ptrdiff_type_node)); + + (*lang_hooks.decls.pushdecl) + (build_decl (TYPE_DECL, get_identifier ("__builtin_size_t"), + sizetype)); + if (TREE_CODE (va_list_type_node) == ARRAY_TYPE) { va_list_arg_type_node = va_list_ref_type_node = @@ -3317,121 +3342,137 @@ c_common_nodes_and_builtins (void) } #define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \ - builtin_types[ENUM] = VALUE; -#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ - def_fn_type (ENUM, RETURN, 0, 0); -#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \ - def_fn_type (ENUM, RETURN, 0, 1, ARG1); -#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \ - def_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2); -#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ - def_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3); -#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ - def_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4); -#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ - def_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5); -#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ - ARG6) \ - def_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6); -#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ - ARG6, ARG7) \ - def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); -#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ - def_fn_type (ENUM, RETURN, 1, 0); -#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ - def_fn_type (ENUM, RETURN, 1, 1, ARG1); -#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ - def_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2); -#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ - def_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3); -#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ - def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4); -#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ - def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5); -#define DEF_POINTER_TYPE(ENUM, TYPE) \ - builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]); - + builtin_types[(int) ENUM] = VALUE; +#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ + builtin_types[(int) ENUM] \ + = build_function_type (builtin_types[(int) RETURN], \ + void_list_node); +#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \ + builtin_types[(int) ENUM] \ + = build_function_type (builtin_types[(int) RETURN], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG1], \ + void_list_node)); +#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \ + builtin_types[(int) ENUM] \ + = build_function_type \ + (builtin_types[(int) RETURN], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG1], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG2], \ + void_list_node))); +#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ + builtin_types[(int) ENUM] \ + = build_function_type \ + (builtin_types[(int) RETURN], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG1], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG2], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG3], \ + void_list_node)))); +#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ + builtin_types[(int) ENUM] \ + = build_function_type \ + (builtin_types[(int) RETURN], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG1], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG2], \ + tree_cons \ + (NULL_TREE, \ + builtin_types[(int) ARG3], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG4], \ + void_list_node))))); +#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ + builtin_types[(int) ENUM] \ + = build_function_type (builtin_types[(int) RETURN], NULL_TREE); +#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ + builtin_types[(int) ENUM] \ + = build_function_type (builtin_types[(int) RETURN], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG1], \ + NULL_TREE)); + +#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ + builtin_types[(int) ENUM] \ + = build_function_type \ + (builtin_types[(int) RETURN], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG1], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG2], \ + NULL_TREE))); + +#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ + builtin_types[(int) ENUM] \ + = build_function_type \ + (builtin_types[(int) RETURN], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG1], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG2], \ + tree_cons (NULL_TREE, \ + builtin_types[(int) ARG3], \ + NULL_TREE)))); + +#define DEF_POINTER_TYPE(ENUM, TYPE) \ + builtin_types[(int) ENUM] \ + = build_pointer_type (builtin_types[(int) TYPE]); #include "builtin-types.def" - #undef DEF_PRIMITIVE_TYPE #undef DEF_FUNCTION_TYPE_1 #undef DEF_FUNCTION_TYPE_2 #undef DEF_FUNCTION_TYPE_3 #undef DEF_FUNCTION_TYPE_4 -#undef DEF_FUNCTION_TYPE_5 -#undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 #undef DEF_FUNCTION_TYPE_VAR_3 -#undef DEF_FUNCTION_TYPE_VAR_4 -#undef DEF_FUNCTION_TYPE_VAR_5 #undef DEF_POINTER_TYPE - builtin_types[(int) BT_LAST] = NULL_TREE; c_init_attributes (); -#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \ - NONANSI_P, ATTRS, IMPLICIT, COND) \ - if (NAME && COND) \ - def_builtin_1 (ENUM, NAME, CLASS, \ - builtin_types[(int) TYPE], \ - builtin_types[(int) LIBTYPE], \ - BOTH_P, FALLBACK_P, NONANSI_P, \ - built_in_attributes[(int) ATTRS], IMPLICIT); +#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, \ + BOTH_P, FALLBACK_P, NONANSI_P, ATTRS, IMPLICIT) \ + if (NAME) \ + { \ + tree decl; \ + \ + if (strncmp (NAME, "__builtin_", strlen ("__builtin_")) != 0) \ + abort (); \ + \ + if (!BOTH_P) \ + decl = builtin_function (NAME, builtin_types[TYPE], ENUM, \ + CLASS, \ + (FALLBACK_P \ + ? (NAME + strlen ("__builtin_")) \ + : NULL), \ + built_in_attributes[(int) ATTRS]); \ + else \ + decl = builtin_function_2 (NAME, \ + NAME + strlen ("__builtin_"), \ + builtin_types[TYPE], \ + builtin_types[LIBTYPE], \ + ENUM, \ + CLASS, \ + FALLBACK_P, \ + NONANSI_P, \ + built_in_attributes[(int) ATTRS]); \ + \ + built_in_decls[(int) ENUM] = decl; \ + if (IMPLICIT) \ + implicit_built_in_decls[(int) ENUM] = decl; \ + } #include "builtins.def" #undef DEF_BUILTIN - build_common_builtin_nodes (); - - targetm.init_builtins (); - if (flag_mudflap) - mudflap_init (); + (*targetm.init_builtins) (); main_identifier_node = get_identifier ("main"); - - /* Create the built-in __null node. It is important that this is - not shared. */ - null_node = make_node (INTEGER_CST); - TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0); - - /* Since builtin_types isn't gc'ed, don't export these nodes. */ - memset (builtin_types, 0, sizeof (builtin_types)); -} - -/* Look up the function in built_in_decls that corresponds to DECL - and set ASMSPEC as its user assembler name. DECL must be a - function decl that declares a builtin. */ - -void -set_builtin_user_assembler_name (tree decl, const char *asmspec) -{ - tree builtin; - gcc_assert (TREE_CODE (decl) == FUNCTION_DECL - && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL - && asmspec != 0); - - builtin = built_in_decls [DECL_FUNCTION_CODE (decl)]; - set_user_assembler_name (builtin, asmspec); - if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMCPY) - init_block_move_fn (asmspec); - else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMSET) - init_block_clear_fn (asmspec); -} - -/* The number of named compound-literals generated thus far. */ -static GTY(()) int compound_literal_number; - -/* Set DECL_NAME for DECL, a VAR_DECL for a compound-literal. */ - -void -set_compound_literal_name (tree decl) -{ - char *name; - ASM_FORMAT_PRIVATE_NAME (name, "__compound_literal", - compound_literal_number); - compound_literal_number++; - DECL_NAME (decl) = get_identifier (name); } tree @@ -3459,13 +3500,13 @@ void disable_builtin_function (const char *name) { if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0) - error ("cannot disable built-in function %qs", name); + error ("cannot disable built-in function `%s'", name); else { - disabled_builtin *new_disabled_builtin = XNEW (disabled_builtin); - new_disabled_builtin->name = name; - new_disabled_builtin->next = disabled_builtins; - disabled_builtins = new_disabled_builtin; + disabled_builtin *new = xmalloc (sizeof (disabled_builtin)); + new->name = name; + new->next = disabled_builtins; + disabled_builtins = new; } } @@ -3486,42 +3527,39 @@ builtin_function_disabled_p (const char *name) } -/* Worker for DEF_BUILTIN. - Possibly define a builtin function with one or two names. - Does not declare a non-__builtin_ function if flag_no_builtin, or if - nonansi_p and flag_no_nonansi_builtin. */ +/* Possibly define a builtin function with one or two names. BUILTIN_NAME + is an __builtin_-prefixed name; NAME is the ordinary name; one or both + of these may be NULL (though both being NULL is useless). + BUILTIN_TYPE is the type of the __builtin_-prefixed function; + TYPE is the type of the function with the ordinary name. These + may differ if the ordinary name is declared with a looser type to avoid + conflicts with headers. FUNCTION_CODE and CLASS are as for + builtin_function. If LIBRARY_NAME_P is nonzero, NAME is passed as + the LIBRARY_NAME parameter to builtin_function when declaring BUILTIN_NAME. + If NONANSI_P is nonzero, the name NAME is treated as a non-ANSI name; + ATTRS is the tree list representing the builtin's function attributes. + Returns the declaration of BUILTIN_NAME, if any, otherwise + the declaration of NAME. Does not declare NAME if flag_no_builtin, + or if NONANSI_P and flag_no_nonansi_builtin. */ -static void -def_builtin_1 (enum built_in_function fncode, - const char *name, - enum built_in_class fnclass, - tree fntype, tree libtype, - bool both_p, bool fallback_p, bool nonansi_p, - tree fnattrs, bool implicit_p) +static tree +builtin_function_2 (const char *builtin_name, const char *name, + tree builtin_type, tree type, int function_code, + enum built_in_class class, int library_name_p, + int nonansi_p, tree attrs) { - tree decl; - const char *libname; - - if (fntype == error_mark_node) - return; + tree bdecl = NULL_TREE; + tree decl = NULL_TREE; - gcc_assert ((!both_p && !fallback_p) - || !strncmp (name, "__builtin_", - strlen ("__builtin_"))); + if (builtin_name != 0) + bdecl = builtin_function (builtin_name, builtin_type, function_code, + class, library_name_p ? name : NULL, attrs); - libname = name + strlen ("__builtin_"); - decl = lang_hooks.builtin_function (name, fntype, fncode, fnclass, - (fallback_p ? libname : NULL), - fnattrs); - if (both_p - && !flag_no_builtin && !builtin_function_disabled_p (libname) + if (name != 0 && !flag_no_builtin && !builtin_function_disabled_p (name) && !(nonansi_p && flag_no_nonansi_builtin)) - lang_hooks.builtin_function (libname, libtype, fncode, fnclass, - NULL, fnattrs); + decl = builtin_function (name, type, function_code, class, NULL, attrs); - built_in_decls[(int) fncode] = decl; - if (implicit_p) - implicit_built_in_decls[(int) fncode] = decl; + return (bdecl != 0 ? bdecl : decl); } /* Nonzero if the type T promotes to int. This is (nearly) the @@ -3565,9 +3603,6 @@ self_promoting_args_p (tree parms) { tree type = TREE_VALUE (t); - if (type == error_mark_node) - continue; - if (TREE_CHAIN (t) == 0 && type != void_type_node) return 0; @@ -3604,6 +3639,225 @@ strip_pointer_operator (tree t) return t; } +static tree expand_unordered_cmp (tree, tree, enum tree_code, enum tree_code); + +/* Expand a call to an unordered comparison function such as + __builtin_isgreater(). FUNCTION is the function's declaration and + PARAMS a list of the values passed. For __builtin_isunordered(), + UNORDERED_CODE is UNORDERED_EXPR and ORDERED_CODE is NOP_EXPR. In + other cases, UNORDERED_CODE and ORDERED_CODE are comparison codes + that give the opposite of the desired result. UNORDERED_CODE is + used for modes that can hold NaNs and ORDERED_CODE is used for the + rest. */ + +static tree +expand_unordered_cmp (tree function, tree params, + enum tree_code unordered_code, + enum tree_code ordered_code) +{ + tree arg0, arg1, type; + enum tree_code code0, code1; + + /* Check that we have exactly two arguments. */ + if (params == 0 || TREE_CHAIN (params) == 0) + { + error ("too few arguments to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (function))); + return error_mark_node; + } + else if (TREE_CHAIN (TREE_CHAIN (params)) != 0) + { + error ("too many arguments to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (function))); + return error_mark_node; + } + + arg0 = TREE_VALUE (params); + arg1 = TREE_VALUE (TREE_CHAIN (params)); + + code0 = TREE_CODE (TREE_TYPE (arg0)); + code1 = TREE_CODE (TREE_TYPE (arg1)); + + /* Make sure that the arguments have a common type of REAL. */ + type = 0; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + type = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)); + + if (type == 0 || TREE_CODE (type) != REAL_TYPE) + { + error ("non-floating-point argument to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (function))); + return error_mark_node; + } + + if (unordered_code == UNORDERED_EXPR) + { + if (MODE_HAS_NANS (TYPE_MODE (type))) + return build_binary_op (unordered_code, + convert (type, arg0), + convert (type, arg1), + 0); + else + return integer_zero_node; + } + + return build_unary_op (TRUTH_NOT_EXPR, + build_binary_op (MODE_HAS_NANS (TYPE_MODE (type)) + ? unordered_code + : ordered_code, + convert (type, arg0), + convert (type, arg1), + 0), + 0); +} + + +/* Recognize certain built-in functions so we can make tree-codes + other than CALL_EXPR. We do this when it enables fold-const.c + to do something useful. */ +/* ??? By rights this should go in builtins.c, but only C and C++ + implement build_{binary,unary}_op. Not exactly sure what bits + of functionality are actually needed from those functions, or + where the similar functionality exists in the other front ends. */ + +tree +expand_tree_builtin (tree function, tree params, tree coerced_params) +{ + if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL) + return NULL_TREE; + + switch (DECL_FUNCTION_CODE (function)) + { + case BUILT_IN_ABS: + case BUILT_IN_LABS: + case BUILT_IN_LLABS: + case BUILT_IN_IMAXABS: + case BUILT_IN_FABS: + case BUILT_IN_FABSL: + case BUILT_IN_FABSF: + if (coerced_params == 0) + return integer_zero_node; + return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0); + + case BUILT_IN_CONJ: + case BUILT_IN_CONJF: + case BUILT_IN_CONJL: + if (coerced_params == 0) + return integer_zero_node; + return build_unary_op (CONJ_EXPR, TREE_VALUE (coerced_params), 0); + + case BUILT_IN_CREAL: + case BUILT_IN_CREALF: + case BUILT_IN_CREALL: + if (coerced_params == 0) + return integer_zero_node; + return non_lvalue (build_unary_op (REALPART_EXPR, + TREE_VALUE (coerced_params), 0)); + + case BUILT_IN_CIMAG: + case BUILT_IN_CIMAGF: + case BUILT_IN_CIMAGL: + if (coerced_params == 0) + return integer_zero_node; + return non_lvalue (build_unary_op (IMAGPART_EXPR, + TREE_VALUE (coerced_params), 0)); + + case BUILT_IN_ISGREATER: + return expand_unordered_cmp (function, params, UNLE_EXPR, LE_EXPR); + + case BUILT_IN_ISGREATEREQUAL: + return expand_unordered_cmp (function, params, UNLT_EXPR, LT_EXPR); + + case BUILT_IN_ISLESS: + return expand_unordered_cmp (function, params, UNGE_EXPR, GE_EXPR); + + case BUILT_IN_ISLESSEQUAL: + return expand_unordered_cmp (function, params, UNGT_EXPR, GT_EXPR); + + case BUILT_IN_ISLESSGREATER: + return expand_unordered_cmp (function, params, UNEQ_EXPR, EQ_EXPR); + + case BUILT_IN_ISUNORDERED: + return expand_unordered_cmp (function, params, UNORDERED_EXPR, NOP_EXPR); + + default: + break; + } + + return NULL_TREE; +} + +/* Walk the statement tree, rooted at *tp. Apply FUNC to all the + sub-trees of *TP in a pre-order traversal. FUNC is called with the + DATA and the address of each sub-tree. If FUNC returns a non-NULL + value, the traversal is aborted, and the value returned by FUNC is + returned. If FUNC sets WALK_SUBTREES to zero, then the subtrees of + the node being visited are not walked. + + We don't need a without_duplicates variant of this one because the + statement tree is a tree, not a graph. */ + +tree +walk_stmt_tree (tree *tp, walk_tree_fn func, void *data) +{ + enum tree_code code; + int walk_subtrees; + tree result; + int i, len; + +#define WALK_SUBTREE(NODE) \ + do \ + { \ + result = walk_stmt_tree (&(NODE), func, data); \ + if (result) \ + return result; \ + } \ + while (0) + + /* Skip empty subtrees. */ + if (!*tp) + return NULL_TREE; + + /* Skip subtrees below non-statement nodes. */ + if (!STATEMENT_CODE_P (TREE_CODE (*tp))) + return NULL_TREE; + + /* Call the function. */ + walk_subtrees = 1; + result = (*func) (tp, &walk_subtrees, data); + + /* If we found something, return it. */ + if (result) + return result; + + /* FUNC may have modified the tree, recheck that we're looking at a + statement node. */ + code = TREE_CODE (*tp); + if (!STATEMENT_CODE_P (code)) + return NULL_TREE; + + /* Visit the subtrees unless FUNC decided that there was nothing + interesting below this point in the tree. */ + if (walk_subtrees) + { + /* Walk over all the sub-trees of this operand. Statement nodes + never contain RTL, and we needn't worry about TARGET_EXPRs. */ + len = TREE_CODE_LENGTH (code); + + /* Go through the subtrees. We need to do this in forward order so + that the scope of a FOR_EXPR is handled properly. */ + for (i = 0; i < len; ++i) + WALK_SUBTREE (TREE_OPERAND (*tp, i)); + } + + /* Finally visit the chain. This can be tail-recursion optimized if + we write it this way. */ + return walk_stmt_tree (&TREE_CHAIN (*tp), func, data); + +#undef WALK_SUBTREE +} + /* Used to compare case labels. K1 and K2 are actually tree nodes representing case labels, or NULL_TREE for a `default' label. Returns -1 if K1 is ordered before K2, -1 if K1 is ordered after @@ -3628,12 +3882,12 @@ case_compare (splay_tree_key k1, splay_tree_key k2) case label was declared using the usual C/C++ syntax, rather than the GNU case range extension. CASES is a tree containing all the case ranges processed so far; COND is the condition for the - switch-statement itself. Returns the CASE_LABEL_EXPR created, or - ERROR_MARK_NODE if no CASE_LABEL_EXPR is created. */ + switch-statement itself. Returns the CASE_LABEL created, or + ERROR_MARK_NODE if no CASE_LABEL is created. */ tree -c_add_case_label (splay_tree cases, tree cond, tree orig_type, - tree low_value, tree high_value) +c_add_case_label (splay_tree cases, tree cond, tree low_value, + tree high_value) { tree type; tree label; @@ -3641,21 +3895,25 @@ c_add_case_label (splay_tree cases, tree cond, tree orig_type, splay_tree_node node; /* Create the LABEL_DECL itself. */ - label = create_artificial_label (); + label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + DECL_CONTEXT (label) = current_function_decl; /* If there was an error processing the switch condition, bail now before we get more confused. */ if (!cond || cond == error_mark_node) - goto error_out; + { + /* Add a label anyhow so that the back-end doesn't think that + the beginning of the switch is unreachable. */ + if (!cases->root) + add_stmt (build_case_label (NULL_TREE, NULL_TREE, label)); + return error_mark_node; + } if ((low_value && TREE_TYPE (low_value) && POINTER_TYPE_P (TREE_TYPE (low_value))) || (high_value && TREE_TYPE (high_value) && POINTER_TYPE_P (TREE_TYPE (high_value)))) - { - error ("pointers are not permitted as case values"); - goto error_out; - } + error ("pointers are not permitted as case values"); /* Case ranges are a GNU extension. */ if (high_value && pedantic) @@ -3666,35 +3924,29 @@ c_add_case_label (splay_tree cases, tree cond, tree orig_type, { low_value = check_case_value (low_value); low_value = convert_and_check (type, low_value); - if (low_value == error_mark_node) - goto error_out; } if (high_value) { high_value = check_case_value (high_value); high_value = convert_and_check (type, high_value); - if (high_value == error_mark_node) - goto error_out; } - if (low_value && high_value) + /* If an error has occurred, bail out now. */ + if (low_value == error_mark_node || high_value == error_mark_node) { - /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't - really a case range, even though it was written that way. - Remove the HIGH_VALUE to simplify later processing. */ - if (tree_int_cst_equal (low_value, high_value)) - high_value = NULL_TREE; - else if (!tree_int_cst_lt (low_value, high_value)) - warning (0, "empty range specified"); + if (!cases->root) + add_stmt (build_case_label (NULL_TREE, NULL_TREE, label)); + return error_mark_node; } - /* See if the case is in range of the type of the original testing - expression. If both low_value and high_value are out of range, - don't insert the case label and return NULL_TREE. */ - if (low_value - && !check_case_bounds (type, orig_type, - &low_value, high_value ? &high_value : NULL)) - return NULL_TREE; + /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't + really a case range, even though it was written that way. Remove + the HIGH_VALUE to simplify later processing. */ + if (tree_int_cst_equal (low_value, high_value)) + high_value = NULL_TREE; + if (low_value && high_value + && !tree_int_cst_lt (low_value, high_value)) + warning ("empty range specified"); /* Look up the LOW_VALUE in the table of case labels we already have. */ @@ -3741,7 +3993,7 @@ c_add_case_label (splay_tree cases, tree cond, tree orig_type, /* If there was an overlap, issue an error. */ if (node) { - tree duplicate = CASE_LABEL ((tree) node->value); + tree duplicate = CASE_LABEL_DECL ((tree) node->value); if (high_value) { @@ -3758,7 +4010,8 @@ c_add_case_label (splay_tree cases, tree cond, tree orig_type, error ("multiple default labels in one switch"); error ("%Jthis is the first default label", duplicate); } - goto error_out; + if (!cases->root) + add_stmt (build_case_label (NULL_TREE, NULL_TREE, label)); } /* Add a CASE_LABEL to the statement-tree. */ @@ -3769,179 +4022,6 @@ c_add_case_label (splay_tree cases, tree cond, tree orig_type, (splay_tree_value) case_label); return case_label; - - error_out: - /* Add a label so that the back-end doesn't think that the beginning of - the switch is unreachable. Note that we do not add a case label, as - that just leads to duplicates and thence to failure later on. */ - if (!cases->root) - { - tree t = create_artificial_label (); - add_stmt (build_stmt (LABEL_EXPR, t)); - } - return error_mark_node; -} - -/* Subroutines of c_do_switch_warnings, called via splay_tree_foreach. - Used to verify that case values match up with enumerator values. */ - -static void -match_case_to_enum_1 (tree key, tree type, tree label) -{ - char buf[2 + 2*HOST_BITS_PER_WIDE_INT/4 + 1]; - - /* ??? Not working too hard to print the double-word value. - Should perhaps be done with %lwd in the diagnostic routines? */ - if (TREE_INT_CST_HIGH (key) == 0) - snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_UNSIGNED, - TREE_INT_CST_LOW (key)); - else if (!TYPE_UNSIGNED (type) - && TREE_INT_CST_HIGH (key) == -1 - && TREE_INT_CST_LOW (key) != 0) - snprintf (buf, sizeof (buf), "-" HOST_WIDE_INT_PRINT_UNSIGNED, - -TREE_INT_CST_LOW (key)); - else - snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_DOUBLE_HEX, - TREE_INT_CST_HIGH (key), TREE_INT_CST_LOW (key)); - - if (TYPE_NAME (type) == 0) - warning (0, "%Jcase value %qs not in enumerated type", - CASE_LABEL (label), buf); - else - warning (0, "%Jcase value %qs not in enumerated type %qT", - CASE_LABEL (label), buf, type); -} - -/* Subroutine of c_do_switch_warnings, called via splay_tree_foreach. - Used to verify that case values match up with enumerator values. */ - -static int -match_case_to_enum (splay_tree_node node, void *data) -{ - tree label = (tree) node->value; - tree type = (tree) data; - - /* Skip default case. */ - if (!CASE_LOW (label)) - return 0; - - /* If CASE_LOW_SEEN is not set, that means CASE_LOW did not appear - when we did our enum->case scan. Reset our scratch bit after. */ - if (!CASE_LOW_SEEN (label)) - match_case_to_enum_1 (CASE_LOW (label), type, label); - else - CASE_LOW_SEEN (label) = 0; - - /* If CASE_HIGH is non-null, we have a range. If CASE_HIGH_SEEN is - not set, that means that CASE_HIGH did not appear when we did our - enum->case scan. Reset our scratch bit after. */ - if (CASE_HIGH (label)) - { - if (!CASE_HIGH_SEEN (label)) - match_case_to_enum_1 (CASE_HIGH (label), type, label); - else - CASE_HIGH_SEEN (label) = 0; - } - - return 0; -} - -/* Handle -Wswitch*. Called from the front end after parsing the - switch construct. */ -/* ??? Should probably be somewhere generic, since other languages - besides C and C++ would want this. At the moment, however, C/C++ - are the only tree-ssa languages that support enumerations at all, - so the point is moot. */ - -void -c_do_switch_warnings (splay_tree cases, location_t switch_location, - tree type, tree cond) -{ - splay_tree_node default_node; - splay_tree_node node; - tree chain; - - if (!warn_switch && !warn_switch_enum && !warn_switch_default) - return; - - default_node = splay_tree_lookup (cases, (splay_tree_key) NULL); - if (!default_node) - warning (OPT_Wswitch_default, "%Hswitch missing default case", - &switch_location); - - /* From here on, we only care about about enumerated types. */ - if (!type || TREE_CODE (type) != ENUMERAL_TYPE) - return; - - /* If the switch expression was an enumerated type, check that - exactly all enumeration literals are covered by the cases. - The check is made when -Wswitch was specified and there is no - default case, or when -Wswitch-enum was specified. */ - - if (!warn_switch_enum - && !(warn_switch && !default_node)) - return; - - /* Clearing COND if it is not an integer constant simplifies - the tests inside the loop below. */ - if (TREE_CODE (cond) != INTEGER_CST) - cond = NULL_TREE; - - /* The time complexity here is O(N*lg(N)) worst case, but for the - common case of monotonically increasing enumerators, it is - O(N), since the nature of the splay tree will keep the next - element adjacent to the root at all times. */ - - for (chain = TYPE_VALUES (type); chain; chain = TREE_CHAIN (chain)) - { - tree value = TREE_VALUE (chain); - node = splay_tree_lookup (cases, (splay_tree_key) value); - if (node) - { - /* Mark the CASE_LOW part of the case entry as seen. */ - tree label = (tree) node->value; - CASE_LOW_SEEN (label) = 1; - continue; - } - - /* Even though there wasn't an exact match, there might be a - case range which includes the enumator's value. */ - node = splay_tree_predecessor (cases, (splay_tree_key) value); - if (node && CASE_HIGH ((tree) node->value)) - { - tree label = (tree) node->value; - int cmp = tree_int_cst_compare (CASE_HIGH (label), value); - if (cmp >= 0) - { - /* If we match the upper bound exactly, mark the CASE_HIGH - part of the case entry as seen. */ - if (cmp == 0) - CASE_HIGH_SEEN (label) = 1; - continue; - } - } - - /* We've now determined that this enumerated literal isn't - handled by the case labels of the switch statement. */ - - /* If the switch expression is a constant, we only really care - about whether that constant is handled by the switch. */ - if (cond && tree_int_cst_compare (cond, value)) - continue; - - warning (0, "%Henumeration value %qE not handled in switch", - &switch_location, TREE_PURPOSE (chain)); - } - - /* Warn if there are case expressions that don't correspond to - enumerators. This can occur since C and C++ don't enforce - type-checking of assignments to enumeration variables. - - The time complexity here is now always O(N) worst case, since - we should have marked both the lower bound and upper bound of - every disjoint case label, with CASE_LOW_SEEN and CASE_HIGH_SEEN - above. This scan also resets those fields. */ - splay_tree_foreach (cases, match_case_to_enum, type); } /* Finish an expression taking the address of LABEL (an @@ -3965,6 +4045,7 @@ finish_label_address_expr (tree label) { TREE_USED (label) = 1; result = build1 (ADDR_EXPR, ptr_type_node, label); + TREE_CONSTANT (result) = 1; /* The current function in not necessarily uninlinable. Computed gotos are incompatible with inlining, but the value here could be used only in a diagnostic, for example. */ @@ -3974,17 +4055,96 @@ finish_label_address_expr (tree label) } /* Hook used by expand_expr to expand language-specific tree codes. */ -/* The only things that should go here are bits needed to expand - constant initializers. Everything else should be handled by the - gimplification routines. */ rtx -c_expand_expr (tree exp, rtx target, enum machine_mode tmode, +c_expand_expr (tree exp, rtx target, enum machine_mode tmode, int modifier /* Actually enum_modifier. */, rtx *alt_rtl) { switch (TREE_CODE (exp)) { + case STMT_EXPR: + { + tree rtl_expr; + rtx result; + bool preserve_result = false; + + if (STMT_EXPR_WARN_UNUSED_RESULT (exp) && target == const0_rtx) + { + tree stmt = STMT_EXPR_STMT (exp); + tree scope; + + for (scope = COMPOUND_BODY (stmt); + scope && TREE_CODE (scope) != SCOPE_STMT; + scope = TREE_CHAIN (scope)); + + if (scope && SCOPE_STMT_BLOCK (scope)) + warning ("%Hignoring return value of `%D', " + "declared with attribute warn_unused_result", + &expr_wfl_stack->location, + BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope))); + else + warning ("%Hignoring return value of function " + "declared with attribute warn_unused_result", + &expr_wfl_stack->location); + } + + /* Since expand_expr_stmt calls free_temp_slots after every + expression statement, we must call push_temp_slots here. + Otherwise, any temporaries in use now would be considered + out-of-scope after the first EXPR_STMT from within the + STMT_EXPR. */ + push_temp_slots (); + rtl_expr = expand_start_stmt_expr (!STMT_EXPR_NO_SCOPE (exp)); + + /* If we want the result of this expression, find the last + EXPR_STMT in the COMPOUND_STMT and mark it as addressable. */ + if (target != const0_rtx + && TREE_CODE (STMT_EXPR_STMT (exp)) == COMPOUND_STMT + && TREE_CODE (COMPOUND_BODY (STMT_EXPR_STMT (exp))) == SCOPE_STMT) + { + tree expr = COMPOUND_BODY (STMT_EXPR_STMT (exp)); + tree last = TREE_CHAIN (expr); + + while (TREE_CHAIN (last)) + { + expr = last; + last = TREE_CHAIN (last); + } + + if (TREE_CODE (last) == SCOPE_STMT + && TREE_CODE (expr) == EXPR_STMT) + { + /* Otherwise, note that we want the value from the last + expression. */ + TREE_ADDRESSABLE (expr) = 1; + preserve_result = true; + } + } + + expand_stmt (STMT_EXPR_STMT (exp)); + expand_end_stmt_expr (rtl_expr); + + result = expand_expr_real (rtl_expr, target, tmode, modifier, alt_rtl); + if (preserve_result && GET_CODE (result) == MEM) + { + if (GET_MODE (result) != BLKmode) + result = copy_to_reg (result); + else + preserve_temp_slots (result); + } + + /* If the statment-expression does not have a scope, then the + new temporaries we created within it must live beyond the + statement-expression. */ + if (STMT_EXPR_NO_SCOPE (exp)) + preserve_temp_slots (NULL_RTX); + + pop_temp_slots (); + return result; + } + break; + case COMPOUND_LITERAL_EXPR: { /* Initialize the anonymous variable declared in the compound @@ -3995,18 +4155,63 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode, } default: - gcc_unreachable (); + abort (); + } + + abort (); + return NULL; +} + +/* Hook used by safe_from_p to handle language-specific tree codes. */ + +int +c_safe_from_p (rtx target, tree exp) +{ + /* We can see statements here when processing the body of a + statement-expression. For a declaration statement declaring a + variable, look at the variable's initializer. */ + if (TREE_CODE (exp) == DECL_STMT) + { + tree decl = DECL_STMT_DECL (exp); + + if (TREE_CODE (decl) == VAR_DECL + && DECL_INITIAL (decl) + && !safe_from_p (target, DECL_INITIAL (decl), /*top_p=*/0)) + return 0; } + + /* For any statement, we must follow the statement-chain. */ + if (STATEMENT_CODE_P (TREE_CODE (exp)) && TREE_CHAIN (exp)) + return safe_from_p (target, TREE_CHAIN (exp), /*top_p=*/0); + + /* Assume everything else is safe. */ + return 1; +} + +/* Hook used by unsafe_for_reeval to handle language-specific tree codes. */ + +int +c_common_unsafe_for_reeval (tree exp) +{ + /* Statement expressions may not be reevaluated, likewise compound + literals. */ + if (TREE_CODE (exp) == STMT_EXPR + || TREE_CODE (exp) == COMPOUND_LITERAL_EXPR) + return 2; + + /* Walk all other expressions. */ + return -1; } /* Hook used by staticp to handle language-specific tree codes. */ -tree +int c_staticp (tree exp) { - return (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR - && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp)) - ? exp : NULL); + if (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR + && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp))) + return 1; + return 0; } @@ -4023,27 +4228,25 @@ boolean_increment (enum tree_code code, tree arg) switch (code) { case PREINCREMENT_EXPR: - val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res); + val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res); break; case POSTINCREMENT_EXPR: - val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res); + val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res); arg = save_expr (arg); - val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg); - val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val); + val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg); + val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val); break; case PREDECREMENT_EXPR: - val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, - invert_truthvalue (arg)); + val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg)); break; case POSTDECREMENT_EXPR: - val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, - invert_truthvalue (arg)); + val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg)); arg = save_expr (arg); - val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg); - val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val); + val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg); + val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val); break; default: - gcc_unreachable (); + abort (); } TREE_SIDE_EFFECTS (val) = 1; return val; @@ -4058,18 +4261,16 @@ c_stddef_cpp_builtins(void) builtin_define_with_value ("__PTRDIFF_TYPE__", PTRDIFF_TYPE, 0); builtin_define_with_value ("__WCHAR_TYPE__", MODIFIED_WCHAR_TYPE, 0); builtin_define_with_value ("__WINT_TYPE__", WINT_TYPE, 0); - builtin_define_with_value ("__INTMAX_TYPE__", INTMAX_TYPE, 0); - builtin_define_with_value ("__UINTMAX_TYPE__", UINTMAX_TYPE, 0); } static void c_init_attributes (void) { /* Fill in the built_in_attributes array. */ -#define DEF_ATTR_NULL_TREE(ENUM) \ +#define DEF_ATTR_NULL_TREE(ENUM) \ built_in_attributes[(int) ENUM] = NULL_TREE; -#define DEF_ATTR_INT(ENUM, VALUE) \ - built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE); +#define DEF_ATTR_INT(ENUM, VALUE) \ + built_in_attributes[(int) ENUM] = build_int_2 (VALUE, VALUE < 0 ? -1 : 0); #define DEF_ATTR_IDENT(ENUM, STRING) \ built_in_attributes[(int) ENUM] = get_identifier (STRING); #define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \ @@ -4090,31 +4291,39 @@ c_init_attributes (void) struct attribute_spec.handler. */ static tree -handle_packed_attribute (tree *node, tree name, tree ARG_UNUSED (args), +handle_packed_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, int flags, bool *no_add_attrs) { if (TYPE_P (*node)) { if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *node = build_variant_type_copy (*node); + *node = build_type_copy (*node); TYPE_PACKED (*node) = 1; + if (TYPE_MAIN_VARIANT (*node) == *node) + { + /* If it is the main variant, then pack the other variants + too. This happens in, + + struct Foo { + struct Foo const *ptr; // creates a variant w/o packed flag + } __ attribute__((packed)); // packs it now. + */ + tree probe; + + for (probe = *node; probe; probe = TYPE_NEXT_VARIANT (probe)) + TYPE_PACKED (probe) = 1; + } + } else if (TREE_CODE (*node) == FIELD_DECL) - { - if (TYPE_ALIGN (TREE_TYPE (*node)) <= BITS_PER_UNIT) - warning (OPT_Wattributes, - "%qE attribute ignored for field of type %qT", - name, TREE_TYPE (*node)); - else - DECL_PACKED (*node) = 1; - } + DECL_PACKED (*node) = 1; /* We can't set DECL_PACKED for a VAR_DECL, because the bit is used for DECL_REGISTER. It wouldn't mean anything anyway. We can't set DECL_PACKED on the type of a TYPE_DECL, because that changes what the typedef is typing. */ else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -4126,14 +4335,14 @@ handle_packed_attribute (tree *node, tree name, tree ARG_UNUSED (args), static tree handle_nocommon_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (TREE_CODE (*node) == VAR_DECL) DECL_COMMON (*node) = 0; else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -4144,14 +4353,14 @@ handle_nocommon_attribute (tree *node, tree name, struct attribute_spec.handler. */ static tree -handle_common_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) +handle_common_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (TREE_CODE (*node) == VAR_DECL) DECL_COMMON (*node) = 1; else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -4162,8 +4371,8 @@ handle_common_attribute (tree *node, tree name, tree ARG_UNUSED (args), struct attribute_spec.handler. */ static tree -handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) +handle_noreturn_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree type = TREE_TYPE (*node); @@ -4175,10 +4384,10 @@ handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args), TREE_TYPE (*node) = build_pointer_type (build_type_variant (TREE_TYPE (type), - TYPE_READONLY (TREE_TYPE (type)), 1)); + TREE_READONLY (TREE_TYPE (type)), 1)); else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -4190,14 +4399,14 @@ handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args), static tree handle_noinline_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (TREE_CODE (*node) == FUNCTION_DECL) DECL_UNINLINABLE (*node) = 1; else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -4209,8 +4418,8 @@ handle_noinline_attribute (tree *node, tree name, static tree handle_always_inline_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (TREE_CODE (*node) == FUNCTION_DECL) @@ -4220,64 +4429,19 @@ handle_always_inline_attribute (tree *node, tree name, } else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } return NULL_TREE; } -/* Handle a "gnu_inline" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_gnu_inline_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (*node)) - { - /* Do nothing else, just set the attribute. We'll get at - it later with lookup_attribute. */ - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "flatten" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_flatten_attribute (tree *node, tree name, - tree args ATTRIBUTE_UNUSED, - int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - /* Do nothing else, just set the attribute. We'll get at - it later with lookup_attribute. */ - ; - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - - /* Handle a "used" attribute; arguments as in struct attribute_spec.handler. */ static tree -handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) +handle_used_attribute (tree *pnode, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree node = *pnode; @@ -4285,11 +4449,10 @@ handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), || (TREE_CODE (node) == VAR_DECL && TREE_STATIC (node))) { TREE_USED (node) = 1; - DECL_PRESERVE_P (node) = 1; } else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -4300,8 +4463,8 @@ handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), struct attribute_spec.handler. */ static tree -handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int flags, bool *no_add_attrs) +handle_unused_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (DECL_P (*node)) { @@ -4315,56 +4478,26 @@ handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args), TREE_USED (decl) = 1; else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } } else { if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *node = build_variant_type_copy (*node); + *node = build_type_copy (*node); TREE_USED (*node) = 1; } return NULL_TREE; } -/* Handle a "externally_visible" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_externally_visible_attribute (tree *pnode, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - tree node = *pnode; - - if (TREE_CODE (node) == FUNCTION_DECL || TREE_CODE (node) == VAR_DECL) - { - if ((!TREE_STATIC (node) && TREE_CODE (node) != FUNCTION_DECL - && !DECL_EXTERNAL (node)) || !TREE_PUBLIC (node)) - { - warning (OPT_Wattributes, - "%qE attribute have effect only on public objects", name); - *no_add_attrs = true; - } - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - /* Handle a "const" attribute; arguments as in struct attribute_spec.handler. */ static tree -handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) +handle_const_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree type = TREE_TYPE (*node); @@ -4379,7 +4512,7 @@ handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), TREE_THIS_VOLATILE (TREE_TYPE (type)))); else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -4391,46 +4524,42 @@ handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), static tree handle_transparent_union_attribute (tree *node, tree name, - tree ARG_UNUSED (args), int flags, + tree args ATTRIBUTE_UNUSED, int flags, bool *no_add_attrs) { - tree type = NULL; - - *no_add_attrs = true; + tree decl = NULL_TREE; + tree *type = NULL; + int is_type = 0; if (DECL_P (*node)) { - if (TREE_CODE (*node) != TYPE_DECL) - goto ignored; - node = &TREE_TYPE (*node); - type = *node; + decl = *node; + type = &TREE_TYPE (decl); + is_type = TREE_CODE (*node) == TYPE_DECL; } else if (TYPE_P (*node)) - type = *node; - else - goto ignored; + type = node, is_type = 1; - if (TREE_CODE (type) == UNION_TYPE) + if (is_type + && TREE_CODE (*type) == UNION_TYPE + && (decl == 0 + || (TYPE_FIELDS (*type) != 0 + && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type))))) { - /* When IN_PLACE is set, leave the check for FIELDS and MODE to - the code in finish_struct. */ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - { - if (TYPE_FIELDS (type) == NULL_TREE - || TYPE_MODE (type) != DECL_MODE (TYPE_FIELDS (type))) - goto ignored; - - /* A type variant isn't good enough, since we don't a cast - to such a type removed as a no-op. */ - *node = type = build_duplicate_type (type); - } - - TYPE_TRANSPARENT_UNION (type) = 1; - return NULL_TREE; + *type = build_type_copy (*type); + TYPE_TRANSPARENT_UNION (*type) = 1; + } + else if (decl != 0 && TREE_CODE (decl) == PARM_DECL + && TREE_CODE (*type) == UNION_TYPE + && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type))) + DECL_TRANSPARENT_UNION (decl) = 1; + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - ignored: - warning (OPT_Wattributes, "%qE attribute ignored", name); return NULL_TREE; } @@ -4439,8 +4568,8 @@ handle_transparent_union_attribute (tree *node, tree name, static tree handle_constructor_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree decl = *node; @@ -4455,7 +4584,7 @@ handle_constructor_attribute (tree *node, tree name, } else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -4467,8 +4596,8 @@ handle_constructor_attribute (tree *node, tree name, static tree handle_destructor_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree decl = *node; @@ -4483,7 +4612,7 @@ handle_destructor_attribute (tree *node, tree name, } else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -4494,15 +4623,15 @@ handle_destructor_attribute (tree *node, tree name, struct attribute_spec.handler. */ static tree -handle_mode_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) +handle_mode_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree type = *node; *no_add_attrs = true; if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE) - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); else { int j; @@ -4510,12 +4639,12 @@ handle_mode_attribute (tree *node, tree name, tree args, int len = strlen (p); enum machine_mode mode = VOIDmode; tree typefm; - bool valid_mode; + tree ptr_type; if (len > 4 && p[0] == '_' && p[1] == '_' && p[len - 1] == '_' && p[len - 2] == '_') { - char *newp = (char *) alloca (len - 1); + char *newp = alloca (len - 1); strcpy (newp, &p[2]); newp[len - 4] = '\0'; @@ -4524,11 +4653,11 @@ handle_mode_attribute (tree *node, tree name, tree args, /* Change this type to have a type with the specified mode. First check for the special modes. */ - if (!strcmp (p, "byte")) + if (! strcmp (p, "byte")) mode = byte_mode; else if (!strcmp (p, "word")) mode = word_mode; - else if (!strcmp (p, "pointer")) + else if (! strcmp (p, "pointer")) mode = ptr_mode; else for (j = 0; j < NUM_MACHINE_MODES; j++) @@ -4539,107 +4668,76 @@ handle_mode_attribute (tree *node, tree name, tree args, } if (mode == VOIDmode) + error ("unknown machine mode `%s'", p); + else if (0 == (typefm = (*lang_hooks.types.type_for_mode) + (mode, TREE_UNSIGNED (type)))) + error ("no data type for mode `%s'", p); + else if ((TREE_CODE (type) == POINTER_TYPE + || TREE_CODE (type) == REFERENCE_TYPE) + && !(*targetm.valid_pointer_mode) (mode)) + error ("invalid pointer mode `%s'", p); + else { - error ("unknown machine mode %qs", p); - return NULL_TREE; - } - - valid_mode = false; - switch (GET_MODE_CLASS (mode)) - { - case MODE_INT: - case MODE_PARTIAL_INT: - case MODE_FLOAT: - case MODE_DECIMAL_FLOAT: - valid_mode = targetm.scalar_mode_supported_p (mode); - break; - - case MODE_COMPLEX_INT: - case MODE_COMPLEX_FLOAT: - valid_mode = targetm.scalar_mode_supported_p (GET_MODE_INNER (mode)); - break; - - case MODE_VECTOR_INT: - case MODE_VECTOR_FLOAT: - warning (OPT_Wattributes, "specifying vector types with " - "__attribute__ ((mode)) is deprecated"); - warning (OPT_Wattributes, - "use __attribute__ ((vector_size)) instead"); - valid_mode = vector_mode_valid_p (mode); - break; - - default: - break; - } - if (!valid_mode) - { - error ("unable to emulate %qs", p); - return NULL_TREE; - } - - if (POINTER_TYPE_P (type)) - { - tree (*fn)(tree, enum machine_mode, bool); - - if (!targetm.valid_pointer_mode (mode)) + /* If this is a vector, make sure we either have hardware + support, or we can emulate it. */ + if (VECTOR_MODE_P (mode) && !vector_mode_valid_p (mode)) { - error ("invalid pointer mode %qs", p); + error ("unable to emulate '%s'", GET_MODE_NAME (mode)); return NULL_TREE; } if (TREE_CODE (type) == POINTER_TYPE) - fn = build_pointer_type_for_mode; - else - fn = build_reference_type_for_mode; - typefm = fn (TREE_TYPE (type), mode, false); - } - else - typefm = lang_hooks.types.type_for_mode (mode, TYPE_UNSIGNED (type)); - - if (typefm == NULL_TREE) - { - error ("no data type for mode %qs", p); - return NULL_TREE; - } - else if (TREE_CODE (type) == ENUMERAL_TYPE) - { - /* For enumeral types, copy the precision from the integer - type returned above. If not an INTEGER_TYPE, we can't use - this mode for this type. */ - if (TREE_CODE (typefm) != INTEGER_TYPE) { - error ("cannot use mode %qs for enumeral types", p); - return NULL_TREE; + ptr_type = build_pointer_type_for_mode (TREE_TYPE (type), + mode); + *node = ptr_type; } - - if (flags & ATTR_FLAG_TYPE_IN_PLACE) + else if (TREE_CODE (type) == REFERENCE_TYPE) + { + ptr_type = build_reference_type_for_mode (TREE_TYPE (type), + mode); + *node = ptr_type; + } + else if (TREE_CODE (type) == ENUMERAL_TYPE) { + /* For enumeral types, copy the precision from the integer + type returned above. If not an INTEGER_TYPE, we can't use + this mode for this type. */ + if (TREE_CODE (typefm) != INTEGER_TYPE) + { + error ("cannot use mode %qs for enumeral types", p); + return NULL_TREE; + } + + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + type = build_type_copy (type); + + /* We cannot use layout_type here, because that will attempt + to re-layout all variants, corrupting our original. */ TYPE_PRECISION (type) = TYPE_PRECISION (typefm); - typefm = type; + TYPE_MIN_VALUE (type) = TYPE_MIN_VALUE (typefm); + TYPE_MAX_VALUE (type) = TYPE_MAX_VALUE (typefm); + TYPE_SIZE (type) = TYPE_SIZE (typefm); + TYPE_SIZE_UNIT (type) = TYPE_SIZE_UNIT (typefm); + TYPE_MODE (type) = TYPE_MODE (typefm); + if (!TYPE_USER_ALIGN (type)) + TYPE_ALIGN (type) = TYPE_ALIGN (typefm); + + *node = type; } - else + else if (VECTOR_MODE_P (mode) + ? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm)) + : TREE_CODE (type) != TREE_CODE (typefm)) + { - /* We cannot build a type variant, as there's code that assumes - that TYPE_MAIN_VARIANT has the same mode. This includes the - debug generators. Instead, create a subrange type. This - results in all of the enumeral values being emitted only once - in the original, and the subtype gets them by reference. */ - if (TYPE_UNSIGNED (type)) - typefm = make_unsigned_type (TYPE_PRECISION (typefm)); - else - typefm = make_signed_type (TYPE_PRECISION (typefm)); - TREE_TYPE (typefm) = type; + error ("mode `%s' applied to inappropriate type", p); + return NULL_TREE; } - } - else if (VECTOR_MODE_P (mode) - ? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm)) - : TREE_CODE (type) != TREE_CODE (typefm)) - { - error ("mode %qs applied to inappropriate type", p); - return NULL_TREE; - } + else + *node = typefm; - *node = typefm; + /* No need to layout the type here. The caller should do this. */ + } } return NULL_TREE; @@ -4649,25 +4747,23 @@ handle_mode_attribute (tree *node, tree name, tree args, struct attribute_spec.handler. */ static tree -handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) +handle_section_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree decl = *node; if (targetm.have_named_sections) { - user_defined_section_attribute = true; - if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) && TREE_CODE (TREE_VALUE (args)) == STRING_CST) { if (TREE_CODE (decl) == VAR_DECL && current_function_decl != NULL_TREE - && !TREE_STATIC (decl)) + && ! TREE_STATIC (decl)) { error ("%Jsection attribute cannot be specified for " - "local variables", decl); + "local variables", decl); *no_add_attrs = true; } @@ -4677,8 +4773,8 @@ handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args, && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), TREE_STRING_POINTER (TREE_VALUE (args))) != 0) { - error ("section of %q+D conflicts with previous declaration", - *node); + error ("%Jsection of '%D' conflicts with previous declaration", + *node, *node); *no_add_attrs = true; } else @@ -4686,7 +4782,7 @@ handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args, } else { - error ("section attribute not allowed for %q+D", *node); + error ("%Jsection attribute not allowed for '%D'", *node, *node); *no_add_attrs = true; } } @@ -4703,7 +4799,7 @@ handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args, struct attribute_spec.handler. */ static tree -handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, +handle_aligned_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args, int flags, bool *no_add_attrs) { tree decl = NULL_TREE; @@ -4722,6 +4818,12 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, else if (TYPE_P (*node)) type = node, is_type = 1; + /* Strip any NOPs of any kind. */ + while (TREE_CODE (align_expr) == NOP_EXPR + || TREE_CODE (align_expr) == CONVERT_EXPR + || TREE_CODE (align_expr) == NON_LVALUE_EXPR) + align_expr = TREE_OPERAND (align_expr, 0); + if (TREE_CODE (align_expr) != INTEGER_CST) { error ("requested alignment is not a constant"); @@ -4745,14 +4847,14 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, && DECL_ORIGINAL_TYPE (decl) == NULL_TREE) { tree tt = TREE_TYPE (decl); - *type = build_variant_type_copy (*type); + *type = build_type_copy (*type); DECL_ORIGINAL_TYPE (decl) = tt; TYPE_NAME (*type) = decl; TREE_USED (*type) = TREE_USED (decl); TREE_TYPE (decl) = *type; } else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *type = build_variant_type_copy (*type); + *type = build_type_copy (*type); TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT; TYPE_USER_ALIGN (*type) = 1; @@ -4760,7 +4862,7 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, else if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FIELD_DECL) { - error ("alignment may not be specified for %q+D", decl); + error ("%Jalignment may not be specified for '%D'", decl, decl); *no_add_attrs = true; } else @@ -4776,17 +4878,12 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, struct attribute_spec.handler. */ static tree -handle_weak_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), - bool * ARG_UNUSED (no_add_attrs)) +handle_weak_attribute (tree *node, tree name ATTRIBUTE_UNUSED, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs ATTRIBUTE_UNUSED) { - if (TREE_CODE (*node) == FUNCTION_DECL - || TREE_CODE (*node) == VAR_DECL) - declare_weak (*node); - else - warning (OPT_Wattributes, "%qE attribute ignored", name); - + declare_weak (*node); return NULL_TREE; } @@ -4796,35 +4893,24 @@ handle_weak_attribute (tree *node, tree name, static tree handle_alias_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree decl = *node; if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) - || (TREE_CODE (decl) != FUNCTION_DECL - && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) - /* A static variable declaration is always a tentative definition, - but the alias is a non-tentative definition which overrides. */ - || (TREE_CODE (decl) != FUNCTION_DECL - && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl))) - { - error ("%q+D defined both normally and as an alias", decl); + || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl))) + { + error ("%J'%D' defined both normally and as an alias", decl, decl); *no_add_attrs = true; } - - /* Note that the very first time we process a nested declaration, - decl_function_context will not be set. Indeed, *would* never - be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that - we do below. After such frobbery, pushdecl would set the context. - In any case, this is never what we want. */ - else if (decl_function_context (decl) == 0 && current_function_decl == NULL) + else if (decl_function_context (decl) == 0) { tree id; id = TREE_VALUE (args); if (TREE_CODE (id) != STRING_CST) { - error ("alias argument not a string"); + error ("alias arg not a string"); *no_add_attrs = true; return NULL_TREE; } @@ -4835,65 +4921,12 @@ handle_alias_attribute (tree *node, tree name, tree args, if (TREE_CODE (decl) == FUNCTION_DECL) DECL_INITIAL (decl) = error_mark_node; else - { - if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))) - DECL_EXTERNAL (decl) = 1; - else - DECL_EXTERNAL (decl) = 0; - TREE_STATIC (decl) = 1; - } + DECL_EXTERNAL (decl) = 0; } else { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "weakref" attribute; arguments as in struct - attribute_spec.handler. */ - -static tree -handle_weakref_attribute (tree *node, tree ARG_UNUSED (name), tree args, - int flags, bool *no_add_attrs) -{ - tree attr = NULL_TREE; - - /* We must ignore the attribute when it is associated with - local-scoped decls, since attribute alias is ignored and many - such symbols do not even have a DECL_WEAK field. */ - if (decl_function_context (*node) || current_function_decl) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - return NULL_TREE; - } - - /* The idea here is that `weakref("name")' mutates into `weakref, - alias("name")', and weakref without arguments, in turn, - implicitly adds weak. */ - - if (args) - { - attr = tree_cons (get_identifier ("alias"), args, attr); - attr = tree_cons (get_identifier ("weakref"), NULL_TREE, attr); - + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; - - decl_attributes (node, attr, flags); - } - else - { - if (lookup_attribute ("alias", DECL_ATTRIBUTES (*node))) - error ("%Jweakref attribute must appear before alias attribute", - *node); - - /* Can't call declare_weak because it wants this to be TREE_PUBLIC, - and that isn't supported; and because it wants to add it to - the list of weak decls, which isn't helpful. */ - DECL_WEAK (*node) = 1; } return NULL_TREE; @@ -4904,169 +4937,76 @@ handle_weakref_attribute (tree *node, tree ARG_UNUSED (name), tree args, static tree handle_visibility_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), - bool *ARG_UNUSED (no_add_attrs)) + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs) { tree decl = *node; tree id = TREE_VALUE (args); - enum symbol_visibility vis; - if (TYPE_P (*node)) - { - if (TREE_CODE (*node) == ENUMERAL_TYPE) - /* OK */; - else if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE) - { - warning (OPT_Wattributes, "%qE attribute ignored on non-class types", - name); - return NULL_TREE; - } - else if (TYPE_FIELDS (*node)) - { - error ("%qE attribute ignored because %qT is already defined", - name, *node); - return NULL_TREE; - } - } - else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl)) + *no_add_attrs = true; + + if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl)) { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); return NULL_TREE; } if (TREE_CODE (id) != STRING_CST) { - error ("visibility argument not a string"); + error ("visibility arg not a string"); return NULL_TREE; } - /* If this is a type, set the visibility on the type decl. */ - if (TYPE_P (decl)) - { - decl = TYPE_NAME (decl); - if (!decl) - return NULL_TREE; - if (TREE_CODE (decl) == IDENTIFIER_NODE) - { - warning (OPT_Wattributes, "%qE attribute ignored on types", - name); - return NULL_TREE; - } - } - if (strcmp (TREE_STRING_POINTER (id), "default") == 0) - vis = VISIBILITY_DEFAULT; + DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0) - vis = VISIBILITY_INTERNAL; + DECL_VISIBILITY (decl) = VISIBILITY_INTERNAL; else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0) - vis = VISIBILITY_HIDDEN; + DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0) - vis = VISIBILITY_PROTECTED; + DECL_VISIBILITY (decl) = VISIBILITY_PROTECTED; else - { - error ("visibility argument must be one of \"default\", \"hidden\", \"protected\" or \"internal\""); - vis = VISIBILITY_DEFAULT; - } - - if (DECL_VISIBILITY_SPECIFIED (decl) - && vis != DECL_VISIBILITY (decl) - && lookup_attribute ("visibility", (TYPE_P (*node) - ? TYPE_ATTRIBUTES (*node) - : DECL_ATTRIBUTES (decl)))) - error ("%qD redeclared with different visibility", decl); - - DECL_VISIBILITY (decl) = vis; - DECL_VISIBILITY_SPECIFIED (decl) = 1; - - /* Go ahead and attach the attribute to the node as well. This is needed - so we can determine whether we have VISIBILITY_DEFAULT because the - visibility was not specified, or because it was explicitly overridden - from the containing scope. */ + error ("visibility arg must be one of \"default\", \"hidden\", \"protected\" or \"internal\""); return NULL_TREE; } -/* Determine the ELF symbol visibility for DECL, which is either a - variable or a function. It is an error to use this function if a - definition of DECL is not available in this translation unit. - Returns true if the final visibility has been determined by this - function; false if the caller is free to make additional - modifications. */ - -bool -c_determine_visibility (tree decl) -{ - gcc_assert (TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL); - - /* If the user explicitly specified the visibility with an - attribute, honor that. DECL_VISIBILITY will have been set during - the processing of the attribute. We check for an explicit - attribute, rather than just checking DECL_VISIBILITY_SPECIFIED, - to distinguish the use of an attribute from the use of a "#pragma - GCC visibility push(...)"; in the latter case we still want other - considerations to be able to overrule the #pragma. */ - if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl))) - return true; - - /* Anything that is exported must have default visibility. */ - if (TARGET_DLLIMPORT_DECL_ATTRIBUTES - && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))) - { - DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; - DECL_VISIBILITY_SPECIFIED (decl) = 1; - return true; - } - - /* Set default visibility to whatever the user supplied with - visibility_specified depending on #pragma GCC visibility. */ - if (!DECL_VISIBILITY_SPECIFIED (decl)) - { - DECL_VISIBILITY (decl) = default_visibility; - DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma; - } - return false; -} - /* Handle an "tls_model" attribute; arguments as in struct attribute_spec.handler. */ static tree handle_tls_model_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { - tree id; tree decl = *node; - enum tls_model kind; - *no_add_attrs = true; - - if (!DECL_THREAD_LOCAL_P (decl)) + if (! DECL_THREAD_LOCAL (decl)) { - warning (OPT_Wattributes, "%qE attribute ignored", name); - return NULL_TREE; + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - - kind = DECL_TLS_MODEL (decl); - id = TREE_VALUE (args); - if (TREE_CODE (id) != STRING_CST) + else { - error ("tls_model argument not a string"); - return NULL_TREE; - } + tree id; - if (!strcmp (TREE_STRING_POINTER (id), "local-exec")) - kind = TLS_MODEL_LOCAL_EXEC; - else if (!strcmp (TREE_STRING_POINTER (id), "initial-exec")) - kind = TLS_MODEL_INITIAL_EXEC; - else if (!strcmp (TREE_STRING_POINTER (id), "local-dynamic")) - kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC; - else if (!strcmp (TREE_STRING_POINTER (id), "global-dynamic")) - kind = TLS_MODEL_GLOBAL_DYNAMIC; - else - error ("tls_model argument must be one of \"local-exec\", \"initial-exec\", \"local-dynamic\" or \"global-dynamic\""); + id = TREE_VALUE (args); + if (TREE_CODE (id) != STRING_CST) + { + error ("tls_model arg not a string"); + *no_add_attrs = true; + return NULL_TREE; + } + if (strcmp (TREE_STRING_POINTER (id), "local-exec") + && strcmp (TREE_STRING_POINTER (id), "initial-exec") + && strcmp (TREE_STRING_POINTER (id), "local-dynamic") + && strcmp (TREE_STRING_POINTER (id), "global-dynamic")) + { + error ("tls_model arg must be one of \"local-exec\", \"initial-exec\", \"local-dynamic\" or \"global-dynamic\""); + *no_add_attrs = true; + return NULL_TREE; + } + } - DECL_TLS_MODEL (decl) = kind; return NULL_TREE; } @@ -5075,20 +5015,20 @@ handle_tls_model_attribute (tree *node, tree name, tree args, static tree handle_no_instrument_function_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree decl = *node; if (TREE_CODE (decl) != FUNCTION_DECL) { - error ("%J%qE attribute applies only to functions", decl, name); + error ("%J'%E' attribute applies only to functions", decl, name); *no_add_attrs = true; } else if (DECL_INITIAL (decl)) { - error ("%Jcan%'t set %qE attribute after definition", decl, name); + error ("%Jcan't set '%E' attribute after definition", decl, name); *no_add_attrs = true; } else @@ -5101,33 +5041,15 @@ handle_no_instrument_function_attribute (tree *node, tree name, struct attribute_spec.handler. */ static tree -handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - if (TREE_CODE (*node) == FUNCTION_DECL - && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))) - DECL_IS_MALLOC (*node) = 1; - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "returns_twice" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_returns_twice_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) +handle_malloc_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (TREE_CODE (*node) == FUNCTION_DECL) - DECL_IS_RETURNS_TWICE (*node) = 1; + DECL_IS_MALLOC (*node) = 1; + /* ??? TODO: Support types. */ else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -5139,20 +5061,20 @@ handle_returns_twice_attribute (tree *node, tree name, tree ARG_UNUSED (args), static tree handle_no_limit_stack_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree decl = *node; if (TREE_CODE (decl) != FUNCTION_DECL) { - error ("%J%qE attribute applies only to functions", decl, name); + error ("%J'%E' attribute applies only to functions", decl, name); *no_add_attrs = true; } else if (DECL_INITIAL (decl)) { - error ("%Jcan%'t set %qE attribute after definition", decl, name); + error ("%Jcan't set '%E' attribute after definition", decl, name); *no_add_attrs = true; } else @@ -5165,45 +5087,32 @@ handle_no_limit_stack_attribute (tree *node, tree name, struct attribute_spec.handler. */ static tree -handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) +handle_pure_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (TREE_CODE (*node) == FUNCTION_DECL) DECL_IS_PURE (*node) = 1; /* ??? TODO: Support types. */ else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } return NULL_TREE; } -/* Handle a "no vops" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_novops_attribute (tree *node, tree ARG_UNUSED (name), - tree ARG_UNUSED (args), int ARG_UNUSED (flags), - bool *ARG_UNUSED (no_add_attrs)) -{ - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); - DECL_IS_NOVOPS (*node) = 1; - return NULL_TREE; -} - /* Handle a "deprecated" attribute; arguments as in struct attribute_spec.handler. */ static tree handle_deprecated_attribute (tree *node, tree name, - tree ARG_UNUSED (args), int flags, + tree args ATTRIBUTE_UNUSED, int flags, bool *no_add_attrs) { tree type = NULL_TREE; int warn = 0; - tree what = NULL_TREE; + const char *what = NULL; if (DECL_P (*node)) { @@ -5222,7 +5131,7 @@ handle_deprecated_attribute (tree *node, tree name, else if (TYPE_P (*node)) { if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *node = build_variant_type_copy (*node); + *node = build_type_copy (*node); TREE_DEPRECATED (*node) = 1; type = *node; } @@ -5235,44 +5144,52 @@ handle_deprecated_attribute (tree *node, tree name, if (type && TYPE_NAME (type)) { if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) - what = TYPE_NAME (*node); + what = IDENTIFIER_POINTER (TYPE_NAME (*node)); else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL && DECL_NAME (TYPE_NAME (type))) - what = DECL_NAME (TYPE_NAME (type)); + what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); } if (what) - warning (OPT_Wattributes, "%qE attribute ignored for %qE", name, what); + warning ("`%s' attribute ignored for `%s'", + IDENTIFIER_POINTER (name), what); else - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", + IDENTIFIER_POINTER (name)); } return NULL_TREE; } +/* Keep a list of vector type nodes we created in handle_vector_size_attribute, + to prevent us from duplicating type nodes unnecessarily. + The normal mechanism to prevent duplicates is to use type_hash_canon, but + since we want to distinguish types that are essentially identical (except + for their debug representation), we use a local list here. */ +static GTY(()) tree vector_type_node_list = 0; + /* Handle a "vector_size" attribute; arguments as in struct attribute_spec.handler. */ static tree handle_vector_size_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { unsigned HOST_WIDE_INT vecsize, nunits; - enum machine_mode orig_mode; - tree type = *node, new_type, size; + enum machine_mode mode, orig_mode, new_mode; + tree type = *node, new_type = NULL_TREE; + tree type_list_node; *no_add_attrs = true; - size = TREE_VALUE (args); - - if (!host_integerp (size, 1)) + if (! host_integerp (TREE_VALUE (args), 1)) { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); return NULL_TREE; } /* Get the vector size (in bytes). */ - vecsize = tree_low_cst (size, 1); + vecsize = tree_low_cst (TREE_VALUE (args), 1); /* We need to provide for vector pointers, vector arrays, and functions returning vectors. For example: @@ -5292,37 +5209,99 @@ handle_vector_size_attribute (tree *node, tree name, tree args, orig_mode = TYPE_MODE (type); if (TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == VECTOR_TYPE - || (!SCALAR_FLOAT_MODE_P (orig_mode) + || (GET_MODE_CLASS (orig_mode) != MODE_FLOAT && GET_MODE_CLASS (orig_mode) != MODE_INT) - || !host_integerp (TYPE_SIZE_UNIT (type), 1)) + || ! host_integerp (TYPE_SIZE_UNIT (type), 1)) { - error ("invalid vector type for attribute %qE", name); + error ("invalid vector type for attribute `%s'", + IDENTIFIER_POINTER (name)); return NULL_TREE; } - if (vecsize % tree_low_cst (TYPE_SIZE_UNIT (type), 1)) + /* Calculate how many units fit in the vector. */ + nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1); + + /* Find a suitably sized vector. */ + new_mode = VOIDmode; + for (mode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_mode) == MODE_INT + ? MODE_VECTOR_INT + : MODE_VECTOR_FLOAT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (vecsize == GET_MODE_SIZE (mode) + && nunits == (unsigned HOST_WIDE_INT) GET_MODE_NUNITS (mode)) + { + new_mode = mode; + break; + } + + if (new_mode == VOIDmode) { - error ("vector size not an integral multiple of component size"); - return NULL; + error ("no vector mode with the size and type specified could be found"); + return NULL_TREE; } - if (vecsize == 0) + for (type_list_node = vector_type_node_list; type_list_node; + type_list_node = TREE_CHAIN (type_list_node)) { - error ("zero vector size"); - return NULL; + tree other_type = TREE_VALUE (type_list_node); + tree record = TYPE_DEBUG_REPRESENTATION_TYPE (other_type); + tree fields = TYPE_FIELDS (record); + tree field_type = TREE_TYPE (fields); + tree array_type = TREE_TYPE (field_type); + if (TREE_CODE (fields) != FIELD_DECL + || TREE_CODE (field_type) != ARRAY_TYPE) + abort (); + + if (TYPE_MODE (other_type) == mode && type == array_type) + { + new_type = other_type; + break; + } } - /* Calculate how many units fit in the vector. */ - nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1); - if (nunits & (nunits - 1)) + if (new_type == NULL_TREE) { - error ("number of components of the vector not a power of two"); - return NULL_TREE; - } + tree index, array, rt, list_node; + + new_type = (*lang_hooks.types.type_for_mode) (new_mode, + TREE_UNSIGNED (type)); + + if (!new_type) + { + error ("no vector mode with the size and type specified could be found"); + return NULL_TREE; + } + + new_type = build_type_copy (new_type); + + /* If this is a vector, make sure we either have hardware + support, or we can emulate it. */ + if ((GET_MODE_CLASS (mode) == MODE_VECTOR_INT + || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT) + && !vector_mode_valid_p (mode)) + { + error ("unable to emulate '%s'", GET_MODE_NAME (mode)); + return NULL_TREE; + } + + /* Set the debug information here, because this is the only + place where we know the underlying type for a vector made + with vector_size. For debugging purposes we pretend a vector + is an array within a structure. */ + index = build_int_2 (TYPE_VECTOR_SUBPARTS (new_type) - 1, 0); + array = build_array_type (type, build_index_type (index)); + rt = make_node (RECORD_TYPE); + + TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array); + DECL_CONTEXT (TYPE_FIELDS (rt)) = rt; + layout_type (rt); + TYPE_DEBUG_REPRESENTATION_TYPE (new_type) = rt; - new_type = build_vector_type (type, nunits); + list_node = build_tree_list (NULL, new_type); + TREE_CHAIN (list_node) = vector_type_node_list; + vector_type_node_list = list_node; + } /* Build back pointers if needed. */ *node = reconstruct_complex_type (*node, new_type); @@ -5332,8 +5311,8 @@ handle_vector_size_attribute (tree *node, tree name, tree args, /* Handle the "nonnull" attribute. */ static tree -handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), - tree args, int ARG_UNUSED (flags), +handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED, + tree args, int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree type = *node; @@ -5342,12 +5321,12 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), /* If no arguments are specified, all pointer arguments should be non-null. Verify a full prototype is given so that the arguments will have the correct types when we actually check them later. */ - if (!args) + if (! args) { - if (!TYPE_ARG_TYPES (type)) + if (! TYPE_ARG_TYPES (type)) { error ("nonnull attribute without arguments on a non-prototype"); - *no_add_attrs = true; + *no_add_attrs = true; } return NULL_TREE; } @@ -5357,11 +5336,11 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), for (attr_arg_num = 1; args; args = TREE_CHAIN (args)) { tree argument; - unsigned HOST_WIDE_INT arg_num = 0, ck_num; + unsigned HOST_WIDE_INT arg_num, ck_num; - if (!get_nonnull_operand (TREE_VALUE (args), &arg_num)) + if (! get_nonnull_operand (TREE_VALUE (args), &arg_num)) { - error ("nonnull argument has invalid operand number (argument %lu)", + error ("nonnull argument has invalid operand number (arg %lu)", (unsigned long) attr_arg_num); *no_add_attrs = true; return NULL_TREE; @@ -5372,23 +5351,23 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), { for (ck_num = 1; ; ck_num++) { - if (!argument || ck_num == arg_num) + if (! argument || ck_num == arg_num) break; argument = TREE_CHAIN (argument); } - if (!argument + if (! argument || TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE) { - error ("nonnull argument with out-of-range operand number (argument %lu, operand %lu)", + error ("nonnull argument with out-of-range operand number (arg %lu, operand %lu)", (unsigned long) attr_arg_num, (unsigned long) arg_num); *no_add_attrs = true; return NULL_TREE; } - if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE) + if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE) { - error ("nonnull argument references non-pointer operand (argument %lu, operand %lu)", + error ("nonnull argument references non-pointer operand (arg %lu, operand %lu)", (unsigned long) attr_arg_num, (unsigned long) arg_num); *no_add_attrs = true; return NULL_TREE; @@ -5412,90 +5391,22 @@ check_function_nonnull (tree attrs, tree params) { if (is_attribute_p ("nonnull", TREE_PURPOSE (a))) { - args = TREE_VALUE (a); + args = TREE_VALUE (a); - /* Walk the argument list. If we encounter an argument number we - should check for non-null, do it. If the attribute has no args, - then every pointer argument is checked (in which case the check + /* Walk the argument list. If we encounter an argument number we + should check for non-null, do it. If the attribute has no args, + then every pointer argument is checked (in which case the check for pointer type is done in check_nonnull_arg). */ - for (param = params, param_num = 1; ; - param_num++, param = TREE_CHAIN (param)) - { - if (!param) + for (param = params, param_num = 1; ; + param_num++, param = TREE_CHAIN (param)) + { + if (! param) break; - if (!args || nonnull_check_p (args, param_num)) + if (! args || nonnull_check_p (args, param_num)) check_function_arguments_recurse (check_nonnull_arg, NULL, TREE_VALUE (param), param_num); - } - } - } -} - -/* Check that the Nth argument of a function call (counting backwards - from the end) is a (pointer)0. */ - -static void -check_function_sentinel (tree attrs, tree params, tree typelist) -{ - tree attr = lookup_attribute ("sentinel", attrs); - - if (attr) - { - /* Skip over the named arguments. */ - while (typelist && params) - { - typelist = TREE_CHAIN (typelist); - params = TREE_CHAIN (params); - } - - if (typelist || !params) - warning (OPT_Wformat, - "not enough variable arguments to fit a sentinel"); - else - { - tree sentinel, end; - unsigned pos = 0; - - if (TREE_VALUE (attr)) - { - tree p = TREE_VALUE (TREE_VALUE (attr)); - pos = TREE_INT_CST_LOW (p); - } - - sentinel = end = params; - - /* Advance `end' ahead of `sentinel' by `pos' positions. */ - while (pos > 0 && TREE_CHAIN (end)) - { - pos--; - end = TREE_CHAIN (end); - } - if (pos > 0) - { - warning (OPT_Wformat, - "not enough variable arguments to fit a sentinel"); - return; - } - - /* Now advance both until we find the last parameter. */ - while (TREE_CHAIN (end)) - { - end = TREE_CHAIN (end); - sentinel = TREE_CHAIN (sentinel); - } - - /* Validate the sentinel. */ - if ((!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel))) - || !integer_zerop (TREE_VALUE (sentinel))) - /* Although __null (in C++) is only an integer we allow it - nevertheless, as we are guaranteed that it's exactly - as wide as a pointer, and we don't want to force - users to cast the NULL they have written there. - We warn with -Wstrict-null-sentinel, though. */ - && (warn_strict_null_sentinel - || null_node != TREE_VALUE (sentinel))) - warning (OPT_Wformat, "missing sentinel in function call"); + } } } } @@ -5507,13 +5418,12 @@ check_function_sentinel (tree attrs, tree params, tree typelist) static bool nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num) { - unsigned HOST_WIDE_INT arg_num = 0; + unsigned HOST_WIDE_INT arg_num; for (; args; args = TREE_CHAIN (args)) { - bool found = get_nonnull_operand (TREE_VALUE (args), &arg_num); - - gcc_assert (found); + if (! get_nonnull_operand (TREE_VALUE (args), &arg_num)) + abort (); if (arg_num == param_num) return true; @@ -5526,7 +5436,7 @@ nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num) via check_function_arguments_recurse. */ static void -check_nonnull_arg (void * ARG_UNUSED (ctx), tree param, +check_nonnull_arg (void *ctx ATTRIBUTE_UNUSED, tree param, unsigned HOST_WIDE_INT param_num) { /* Just skip checking the argument if it's not a pointer. This can @@ -5537,8 +5447,8 @@ check_nonnull_arg (void * ARG_UNUSED (ctx), tree param, return; if (integer_zerop (param)) - warning (OPT_Wnonnull, "null argument where non-null required " - "(argument %lu)", (unsigned long) param_num); + warning ("null argument where non-null required (arg %lu)", + (unsigned long) param_num); } /* Helper for nonnull attribute handling; fetch the operand number @@ -5547,7 +5457,13 @@ check_nonnull_arg (void * ARG_UNUSED (ctx), tree param, static bool get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp) { - /* Verify the arg number is a constant. */ + /* Strip any conversions from the arg number and verify they + are constants. */ + while (TREE_CODE (arg_num_expr) == NOP_EXPR + || TREE_CODE (arg_num_expr) == CONVERT_EXPR + || TREE_CODE (arg_num_expr) == NON_LVALUE_EXPR) + arg_num_expr = TREE_OPERAND (arg_num_expr, 0); + if (TREE_CODE (arg_num_expr) != INTEGER_CST || TREE_INT_CST_HIGH (arg_num_expr) != 0) return false; @@ -5560,15 +5476,15 @@ get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp) struct attribute_spec.handler. */ static tree -handle_nothrow_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) +handle_nothrow_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (TREE_CODE (*node) == FUNCTION_DECL) TREE_NOTHROW (*node) = 1; /* ??? TODO: Support types. */ else { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -5580,7 +5496,7 @@ handle_nothrow_attribute (tree *node, tree name, tree ARG_UNUSED (args), static tree handle_cleanup_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { tree decl = *node; tree cleanup_id, cleanup_decl; @@ -5591,7 +5507,7 @@ handle_cleanup_attribute (tree *node, tree name, tree args, we'd be missing too much, since we do have attribute constructor. */ if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl)) { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; return NULL_TREE; } @@ -5602,14 +5518,14 @@ handle_cleanup_attribute (tree *node, tree name, tree args, cleanup_id = TREE_VALUE (args); if (TREE_CODE (cleanup_id) != IDENTIFIER_NODE) { - error ("cleanup argument not an identifier"); + error ("cleanup arg not an identifier"); *no_add_attrs = true; return NULL_TREE; } cleanup_decl = lookup_name (cleanup_id); if (!cleanup_decl || TREE_CODE (cleanup_decl) != FUNCTION_DECL) { - error ("cleanup argument not a function"); + error ("cleanup arg not a function"); *no_add_attrs = true; return NULL_TREE; } @@ -5624,71 +5540,22 @@ handle_cleanup_attribute (tree *node, tree name, tree args, static tree handle_warn_unused_result_attribute (tree *node, tree name, - tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { /* Ignore the attribute for functions not returning any value. */ if (VOID_TYPE_P (TREE_TYPE (*node))) { - warning (OPT_Wattributes, "%qE attribute ignored", name); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } return NULL_TREE; } - -/* Handle a "sentinel" attribute. */ - -static tree -handle_sentinel_attribute (tree *node, tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) -{ - tree params = TYPE_ARG_TYPES (*node); - - if (!params) - { - warning (OPT_Wattributes, - "%qE attribute requires prototypes with named arguments", name); - *no_add_attrs = true; - } - else - { - while (TREE_CHAIN (params)) - params = TREE_CHAIN (params); - - if (VOID_TYPE_P (TREE_VALUE (params))) - { - warning (OPT_Wattributes, - "%qE attribute only applies to variadic functions", name); - *no_add_attrs = true; - } - } - - if (args) - { - tree position = TREE_VALUE (args); - - if (TREE_CODE (position) != INTEGER_CST) - { - warning (0, "requested position is not an integer constant"); - *no_add_attrs = true; - } - else - { - if (tree_int_cst_lt (position, integer_zero_node)) - { - warning (0, "requested position is less than zero"); - *no_add_attrs = true; - } - } - } - - return NULL_TREE; -} /* Check for valid arguments being passed to a function. */ void -check_function_arguments (tree attrs, tree params, tree typelist) +check_function_arguments (tree attrs, tree params) { /* Check for null being passed in a pointer argument that must be non-null. We also need to do this if format checking is enabled. */ @@ -5698,11 +5565,8 @@ check_function_arguments (tree attrs, tree params, tree typelist) /* Check for errors in format strings. */ - if (warn_format || warn_missing_format_attribute) - check_function_format (attrs, params); - if (warn_format) - check_function_sentinel (attrs, params, typelist); + check_function_format (NULL, attrs, params); } /* Generic argument checking recursion routine. PARAM is the argument to @@ -5714,13 +5578,11 @@ check_function_arguments_recurse (void (*callback) void *ctx, tree param, unsigned HOST_WIDE_INT param_num) { - if ((TREE_CODE (param) == NOP_EXPR || TREE_CODE (param) == CONVERT_EXPR) - && (TYPE_PRECISION (TREE_TYPE (param)) - == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (param, 0))))) + if (TREE_CODE (param) == NOP_EXPR) { /* Strip coercion. */ check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 0), param_num); + TREE_OPERAND (param, 0), param_num); return; } @@ -5747,9 +5609,14 @@ check_function_arguments_recurse (void (*callback) /* Extract the argument number, which was previously checked to be valid. */ format_num_expr = TREE_VALUE (TREE_VALUE (attrs)); + while (TREE_CODE (format_num_expr) == NOP_EXPR + || TREE_CODE (format_num_expr) == CONVERT_EXPR + || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR) + format_num_expr = TREE_OPERAND (format_num_expr, 0); - gcc_assert (TREE_CODE (format_num_expr) == INTEGER_CST - && !TREE_INT_CST_HIGH (format_num_expr)); + if (TREE_CODE (format_num_expr) != INTEGER_CST + || TREE_INT_CST_HIGH (format_num_expr) != 0) + abort (); format_num = TREE_INT_CST_LOW (format_num_expr); @@ -5777,9 +5644,9 @@ check_function_arguments_recurse (void (*callback) { /* Check both halves of the conditional expression. */ check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 1), param_num); + TREE_OPERAND (param, 1), param_num); check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 2), param_num); + TREE_OPERAND (param, 2), param_num); return; } @@ -5791,9 +5658,8 @@ check_function_arguments_recurse (void (*callback) int field_decl_cmp (const void *x_p, const void *y_p) { - const tree *const x = (const tree *const) x_p; - const tree *const y = (const tree *const) y_p; - + const tree *const x = x_p; + const tree *const y = y_p; if (DECL_NAME (*x) == DECL_NAME (*y)) /* A nontype is "greater" than a type. */ return (TREE_CODE (*y) == TYPE_DECL) - (TREE_CODE (*x) == TYPE_DECL); @@ -5817,8 +5683,8 @@ pointer operator in resort_data. */ static int resort_field_decl_cmp (const void *x_p, const void *y_p) { - const tree *const x = (const tree *const) x_p; - const tree *const y = (const tree *const) y_p; + const tree *const x = x_p; + const tree *const y = y_p; if (DECL_NAME (*x) == DECL_NAME (*y)) /* A nontype is "greater" than a type. */ @@ -5842,634 +5708,205 @@ resort_field_decl_cmp (const void *x_p, const void *y_p) void resort_sorted_fields (void *obj, - void * ARG_UNUSED (orig_obj), - gt_pointer_operator new_value, - void *cookie) + void *orig_obj ATTRIBUTE_UNUSED , + gt_pointer_operator new_value, + void *cookie) { - struct sorted_fields_type *sf = (struct sorted_fields_type *) obj; + struct sorted_fields_type *sf = obj; resort_data.new_value = new_value; resort_data.cookie = cookie; qsort (&sf->elts[0], sf->len, sizeof (tree), - resort_field_decl_cmp); -} - -/* Subroutine of c_parse_error. - Return the result of concatenating LHS and RHS. RHS is really - a string literal, its first character is indicated by RHS_START and - RHS_SIZE is its length (including the terminating NUL character). - - The caller is responsible for deleting the returned pointer. */ - -static char * -catenate_strings (const char *lhs, const char *rhs_start, int rhs_size) -{ - const int lhs_size = strlen (lhs); - char *result = XNEWVEC (char, lhs_size + rhs_size); - strncpy (result, lhs, lhs_size); - strncpy (result + lhs_size, rhs_start, rhs_size); - return result; + resort_field_decl_cmp); } -/* Issue the error given by GMSGID, indicating that it occurred before - TOKEN, which had the associated VALUE. */ - -void -c_parse_error (const char *gmsgid, enum cpp_ttype token, tree value) +/* Used by estimate_num_insns. Estimate number of instructions seen + by given statement. */ +static tree +c_estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) { -#define catenate_messages(M1, M2) catenate_strings ((M1), (M2), sizeof (M2)) - - char *message = NULL; - - if (token == CPP_EOF) - message = catenate_messages (gmsgid, " at end of input"); - else if (token == CPP_CHAR || token == CPP_WCHAR) - { - unsigned int val = TREE_INT_CST_LOW (value); - const char *const ell = (token == CPP_CHAR) ? "" : "L"; - if (val <= UCHAR_MAX && ISGRAPH (val)) - message = catenate_messages (gmsgid, " before %s'%c'"); - else - message = catenate_messages (gmsgid, " before %s'\\x%x'"); - - error (message, ell, val); - free (message); - message = NULL; - } - else if (token == CPP_STRING || token == CPP_WSTRING) - message = catenate_messages (gmsgid, " before string constant"); - else if (token == CPP_NUMBER) - message = catenate_messages (gmsgid, " before numeric constant"); - else if (token == CPP_NAME) - { - message = catenate_messages (gmsgid, " before %qE"); - error (message, value); - free (message); - message = NULL; - } - else if (token == CPP_PRAGMA) - message = catenate_messages (gmsgid, " before %<#pragma%>"); - else if (token == CPP_PRAGMA_EOL) - message = catenate_messages (gmsgid, " before end of line"); - else if (token < N_TTYPES) - { - message = catenate_messages (gmsgid, " before %qs token"); - error (message, cpp_type2name (token)); - free (message); - message = NULL; - } - else - error (gmsgid); + int *count = data; + tree x = *tp; - if (message) + if (TYPE_P (x) || DECL_P (x)) { - error (message); - free (message); + *walk_subtrees = 0; + return NULL; } -#undef catenate_messages -} - -/* Walk a gimplified function and warn for functions whose return value is - ignored and attribute((warn_unused_result)) is set. This is done before - inlining, so we don't have to worry about that. */ - -void -c_warn_unused_result (tree *top_p) -{ - tree t = *top_p; - tree_stmt_iterator i; - tree fdecl, ftype; + /* Assume that constants and references counts nothing. These should + be majorized by amount of operations among them we count later + and are common target of CSE and similar optimizations. */ + if (TREE_CODE_CLASS (TREE_CODE (x)) == 'c' + || TREE_CODE_CLASS (TREE_CODE (x)) == 'r') + return NULL; + switch (TREE_CODE (x)) + { + /* Recognize assignments of large structures and constructors of + big arrays. */ + case MODIFY_EXPR: + case CONSTRUCTOR: + { + HOST_WIDE_INT size; - switch (TREE_CODE (t)) - { - case STATEMENT_LIST: - for (i = tsi_start (*top_p); !tsi_end_p (i); tsi_next (&i)) - c_warn_unused_result (tsi_stmt_ptr (i)); - break; + size = int_size_in_bytes (TREE_TYPE (x)); - case COND_EXPR: - c_warn_unused_result (&COND_EXPR_THEN (t)); - c_warn_unused_result (&COND_EXPR_ELSE (t)); - break; - case BIND_EXPR: - c_warn_unused_result (&BIND_EXPR_BODY (t)); - break; - case TRY_FINALLY_EXPR: - case TRY_CATCH_EXPR: - c_warn_unused_result (&TREE_OPERAND (t, 0)); - c_warn_unused_result (&TREE_OPERAND (t, 1)); - break; - case CATCH_EXPR: - c_warn_unused_result (&CATCH_BODY (t)); - break; - case EH_FILTER_EXPR: - c_warn_unused_result (&EH_FILTER_FAILURE (t)); + if (size < 0 || size > MOVE_MAX_PIECES * MOVE_RATIO) + *count += 10; + else + *count += ((size + MOVE_MAX_PIECES - 1) / MOVE_MAX_PIECES); + } break; - case CALL_EXPR: - if (TREE_USED (t)) - break; - - /* This is a naked call, as opposed to a CALL_EXPR nested inside - a MODIFY_EXPR. All calls whose value is ignored should be - represented like this. Look for the attribute. */ - fdecl = get_callee_fndecl (t); - if (fdecl) - ftype = TREE_TYPE (fdecl); - else - { - ftype = TREE_TYPE (TREE_OPERAND (t, 0)); - /* Look past pointer-to-function to the function type itself. */ - ftype = TREE_TYPE (ftype); - } - - if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype))) - { - if (fdecl) - warning (0, "%Hignoring return value of %qD, " - "declared with attribute warn_unused_result", - EXPR_LOCUS (t), fdecl); - else - warning (0, "%Hignoring return value of function " - "declared with attribute warn_unused_result", - EXPR_LOCUS (t)); - } - break; + { + tree decl = get_callee_fndecl (x); - default: - /* Not a container, not a call, or a call whose value is used. */ + if (decl && DECL_BUILT_IN (decl)) + switch (DECL_FUNCTION_CODE (decl)) + { + case BUILT_IN_CONSTANT_P: + *walk_subtrees = 0; + return NULL_TREE; + case BUILT_IN_EXPECT: + return NULL_TREE; + default: + break; + } + *count += 10; + break; + } + /* Few special cases of expensive operations. This is usefull + to avoid inlining on functions having too many of these. */ + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case RDIV_EXPR: + *count += 10; break; - } -} - -/* Convert a character from the host to the target execution character - set. cpplib handles this, mostly. */ - -HOST_WIDE_INT -c_common_to_target_charset (HOST_WIDE_INT c) -{ - /* Character constants in GCC proper are sign-extended under -fsigned-char, - zero-extended under -fno-signed-char. cpplib insists that characters - and character constants are always unsigned. Hence we must convert - back and forth. */ - cppchar_t uc = ((cppchar_t)c) & ((((cppchar_t)1) << CHAR_BIT)-1); - - uc = cpp_host_to_exec_charset (parse_in, uc); - - if (flag_signed_char) - return ((HOST_WIDE_INT)uc) << (HOST_BITS_PER_WIDE_INT - CHAR_TYPE_SIZE) - >> (HOST_BITS_PER_WIDE_INT - CHAR_TYPE_SIZE); - else - return uc; -} - -/* Build the result of __builtin_offsetof. EXPR is a nested sequence of - component references, with STOP_REF, or alternatively an INDIRECT_REF of - NULL, at the bottom; much like the traditional rendering of offsetof as a - macro. Returns the folded and properly cast result. */ - -static tree -fold_offsetof_1 (tree expr, tree stop_ref) -{ - enum tree_code code = PLUS_EXPR; - tree base, off, t; - - if (expr == stop_ref && TREE_CODE (expr) != ERROR_MARK) - return size_zero_node; - - switch (TREE_CODE (expr)) - { - case ERROR_MARK: - return expr; - - case VAR_DECL: - error ("cannot apply %<offsetof%> to static data member %qD", expr); - return error_mark_node; - - case CALL_EXPR: - error ("cannot apply %<offsetof%> when %<operator[]%> is overloaded"); - return error_mark_node; - - case INTEGER_CST: - gcc_assert (integer_zerop (expr)); - return size_zero_node; - + /* Various containers that will produce no code themselves. */ + case INIT_EXPR: + case TARGET_EXPR: + case BIND_EXPR: + case BLOCK: + case TREE_LIST: + case TREE_VEC: + case IDENTIFIER_NODE: + case PLACEHOLDER_EXPR: + case WITH_CLEANUP_EXPR: + case CLEANUP_POINT_EXPR: case NOP_EXPR: - case INDIRECT_REF: - base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref); - gcc_assert (base == error_mark_node || base == size_zero_node); - return base; - - case COMPONENT_REF: - base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref); - if (base == error_mark_node) - return base; - - t = TREE_OPERAND (expr, 1); - if (DECL_C_BIT_FIELD (t)) - { - error ("attempt to take address of bit-field structure " - "member %qD", t); - return error_mark_node; - } - off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t), - size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), 1) - / BITS_PER_UNIT)); - break; - - case ARRAY_REF: - base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref); - if (base == error_mark_node) - return base; - - t = TREE_OPERAND (expr, 1); - if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0) - { - code = MINUS_EXPR; - t = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t); - } - t = convert (sizetype, t); - off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t); - break; - - case COMPOUND_EXPR: - /* Handle static members of volatile structs. */ - t = TREE_OPERAND (expr, 1); - gcc_assert (TREE_CODE (t) == VAR_DECL); - return fold_offsetof_1 (t, stop_ref); - - default: - gcc_unreachable (); - } - - return size_binop (code, base, off); -} - -tree -fold_offsetof (tree expr, tree stop_ref) -{ - /* Convert back from the internal sizetype to size_t. */ - return convert (size_type_node, fold_offsetof_1 (expr, stop_ref)); -} - -/* Print an error message for an invalid lvalue. USE says - how the lvalue is being used and so selects the error message. */ - -void -lvalue_error (enum lvalue_use use) -{ - switch (use) - { - case lv_assign: - error ("lvalue required as left operand of assignment"); - break; - case lv_increment: - error ("lvalue required as increment operand"); - break; - case lv_decrement: - error ("lvalue required as decrement operand"); - break; - case lv_addressof: - error ("lvalue required as unary %<&%> operand"); + case VIEW_CONVERT_EXPR: + case SAVE_EXPR: + case UNSAVE_EXPR: + case COMPLEX_EXPR: + case REALPART_EXPR: + case IMAGPART_EXPR: + case TRY_CATCH_EXPR: + case TRY_FINALLY_EXPR: + case LABEL_EXPR: + case EXIT_EXPR: + case LABELED_BLOCK_EXPR: + case EXIT_BLOCK_EXPR: + case EXPR_WITH_FILE_LOCATION: + + case EXPR_STMT: + case COMPOUND_STMT: + case RETURN_STMT: + case LABEL_STMT: + case SCOPE_STMT: + case FILE_STMT: + case CASE_LABEL: + case STMT_EXPR: + case CLEANUP_STMT: + + case SIZEOF_EXPR: + case ARROW_EXPR: + case ALIGNOF_EXPR: break; - case lv_asm: - error ("lvalue required in asm statement"); + case DECL_STMT: + /* Do not account static initializers. */ + if (TREE_STATIC (TREE_OPERAND (x, 0))) + *walk_subtrees = 0; break; default: - gcc_unreachable (); + (*count)++; } + return NULL; } - -/* *PTYPE is an incomplete array. Complete it with a domain based on - INITIAL_VALUE. If INITIAL_VALUE is not present, use 1 if DO_DEFAULT - is true. Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered, - 2 if INITIAL_VALUE was NULL, and 3 if INITIAL_VALUE was empty. */ +/* Estimate number of instructions that will be created by expanding the body. */ int -complete_array_type (tree *ptype, tree initial_value, bool do_default) -{ - tree maxindex, type, main_type, elt, unqual_elt; - int failure = 0, quals; - - maxindex = size_zero_node; - if (initial_value) - { - if (TREE_CODE (initial_value) == STRING_CST) - { - int eltsize - = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value))); - maxindex = size_int (TREE_STRING_LENGTH (initial_value)/eltsize - 1); - } - else if (TREE_CODE (initial_value) == CONSTRUCTOR) - { - VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (initial_value); - - if (VEC_empty (constructor_elt, v)) - { - if (pedantic) - failure = 3; - maxindex = integer_minus_one_node; - } - else - { - tree curindex; - unsigned HOST_WIDE_INT cnt; - constructor_elt *ce; - - if (VEC_index (constructor_elt, v, 0)->index) - maxindex = fold_convert (sizetype, - VEC_index (constructor_elt, - v, 0)->index); - curindex = maxindex; - - for (cnt = 1; - VEC_iterate (constructor_elt, v, cnt, ce); - cnt++) - { - if (ce->index) - curindex = fold_convert (sizetype, ce->index); - else - curindex = size_binop (PLUS_EXPR, curindex, size_one_node); - - if (tree_int_cst_lt (maxindex, curindex)) - maxindex = curindex; - } - } - } - else - { - /* Make an error message unless that happened already. */ - if (initial_value != error_mark_node) - failure = 1; - } - } - else - { - failure = 2; - if (!do_default) - return failure; - } - - type = *ptype; - elt = TREE_TYPE (type); - quals = TYPE_QUALS (strip_array_types (elt)); - if (quals == 0) - unqual_elt = elt; - else - unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); - - /* Using build_distinct_type_copy and modifying things afterward instead - of using build_array_type to create a new type preserves all of the - TYPE_LANG_FLAG_? bits that the front end may have set. */ - main_type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); - TREE_TYPE (main_type) = unqual_elt; - TYPE_DOMAIN (main_type) = build_index_type (maxindex); - layout_type (main_type); - - if (quals == 0) - type = main_type; - else - type = c_build_qualified_type (main_type, quals); - - *ptype = type; - return failure; -} - - -/* Used to help initialize the builtin-types.def table. When a type of - the correct size doesn't exist, use error_mark_node instead of NULL. - The later results in segfaults even when a decl using the type doesn't - get invoked. */ - -tree -builtin_type_for_size (int size, bool unsignedp) -{ - tree type = lang_hooks.types.type_for_size (size, unsignedp); - return type ? type : error_mark_node; -} - -/* A helper function for resolve_overloaded_builtin in resolving the - overloaded __sync_ builtins. Returns a positive power of 2 if the - first operand of PARAMS is a pointer to a supported data type. - Returns 0 if an error is encountered. */ - -static int -sync_resolve_size (tree function, tree params) +c_estimate_num_insns (tree decl) { - tree type; - int size; - - if (params == NULL) - { - error ("too few arguments to function %qE", function); - return 0; - } - - type = TREE_TYPE (TREE_VALUE (params)); - if (TREE_CODE (type) != POINTER_TYPE) - goto incompatible; - - type = TREE_TYPE (type); - if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) - goto incompatible; - - size = tree_low_cst (TYPE_SIZE_UNIT (type), 1); - if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16) - return size; - - incompatible: - error ("incompatible type for argument %d of %qE", 1, function); - return 0; -} - -/* A helper function for resolve_overloaded_builtin. Adds casts to - PARAMS to make arguments match up with those of FUNCTION. Drops - the variadic arguments at the end. Returns false if some error - was encountered; true on success. */ - -static bool -sync_resolve_params (tree orig_function, tree function, tree params) -{ - tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (function)); - tree ptype; - int number; - - /* We've declared the implementation functions to use "volatile void *" - as the pointer parameter, so we shouldn't get any complaints from the - call to check_function_arguments what ever type the user used. */ - arg_types = TREE_CHAIN (arg_types); - ptype = TREE_TYPE (TREE_TYPE (TREE_VALUE (params))); - number = 2; - - /* For the rest of the values, we need to cast these to FTYPE, so that we - don't get warnings for passing pointer types, etc. */ - while (arg_types != void_list_node) - { - tree val; - - params = TREE_CHAIN (params); - if (params == NULL) - { - error ("too few arguments to function %qE", orig_function); - return false; - } - - /* ??? Ideally for the first conversion we'd use convert_for_assignment - so that we get warnings for anything that doesn't match the pointer - type. This isn't portable across the C and C++ front ends atm. */ - val = TREE_VALUE (params); - val = convert (ptype, val); - val = convert (TREE_VALUE (arg_types), val); - TREE_VALUE (params) = val; - - arg_types = TREE_CHAIN (arg_types); - number++; - } - - /* The definition of these primitives is variadic, with the remaining - being "an optional list of variables protected by the memory barrier". - No clue what that's supposed to mean, precisely, but we consider all - call-clobbered variables to be protected so we're safe. */ - TREE_CHAIN (params) = NULL; - - return true; + int num = 0; + walk_tree_without_duplicates (&DECL_SAVED_TREE (decl), c_estimate_num_insns_1, &num); + return num; } -/* A helper function for resolve_overloaded_builtin. Adds a cast to - RESULT to make it match the type of the first pointer argument in - PARAMS. */ +/* Used by c_decl_uninit to find where expressions like x = x + 1; */ static tree -sync_resolve_return (tree params, tree result) +c_decl_uninit_1 (tree *t, int *walk_sub_trees, void *x) { - tree ptype = TREE_TYPE (TREE_TYPE (TREE_VALUE (params))); - ptype = TYPE_MAIN_VARIANT (ptype); - return convert (ptype, result); -} - -/* Some builtin functions are placeholders for other expressions. This - function should be called immediately after parsing the call expression - before surrounding code has committed to the type of the expression. - - FUNCTION is the DECL that has been invoked; it is known to be a builtin. - PARAMS is the argument list for the call. The return value is non-null - when expansion is complete, and null if normal processing should - continue. */ - -tree -resolve_overloaded_builtin (tree function, tree params) -{ - enum built_in_function orig_code = DECL_FUNCTION_CODE (function); - switch (DECL_BUILT_IN_CLASS (function)) + /* If x = EXP(&x)EXP, then do not warn about the use of x. */ + if (TREE_CODE (*t) == ADDR_EXPR && TREE_OPERAND (*t, 0) == x) { - case BUILT_IN_NORMAL: - break; - case BUILT_IN_MD: - if (targetm.resolve_overloaded_builtin) - return targetm.resolve_overloaded_builtin (function, params); - else - return NULL_TREE; - default: - return NULL_TREE; - } - - /* Handle BUILT_IN_NORMAL here. */ - switch (orig_code) - { - case BUILT_IN_FETCH_AND_ADD_N: - case BUILT_IN_FETCH_AND_SUB_N: - case BUILT_IN_FETCH_AND_OR_N: - case BUILT_IN_FETCH_AND_AND_N: - case BUILT_IN_FETCH_AND_XOR_N: - case BUILT_IN_FETCH_AND_NAND_N: - case BUILT_IN_ADD_AND_FETCH_N: - case BUILT_IN_SUB_AND_FETCH_N: - case BUILT_IN_OR_AND_FETCH_N: - case BUILT_IN_AND_AND_FETCH_N: - case BUILT_IN_XOR_AND_FETCH_N: - case BUILT_IN_NAND_AND_FETCH_N: - case BUILT_IN_BOOL_COMPARE_AND_SWAP_N: - case BUILT_IN_VAL_COMPARE_AND_SWAP_N: - case BUILT_IN_LOCK_TEST_AND_SET_N: - case BUILT_IN_LOCK_RELEASE_N: - { - int n = sync_resolve_size (function, params); - tree new_function, result; - - if (n == 0) - return error_mark_node; - - new_function = built_in_decls[orig_code + exact_log2 (n) + 1]; - if (!sync_resolve_params (function, new_function, params)) - return error_mark_node; - - result = build_function_call (new_function, params); - if (orig_code != BUILT_IN_BOOL_COMPARE_AND_SWAP_N - && orig_code != BUILT_IN_LOCK_RELEASE_N) - result = sync_resolve_return (params, result); - - return result; - } - - default: + *walk_sub_trees = 0; return NULL_TREE; } + if (*t == x) + return *t; + return NULL_TREE; } -/* Ignoring their sign, return true if two scalar types are the same. */ +/* Find out if a variable is uninitialized based on DECL_INITIAL. */ + bool -same_scalar_type_ignoring_signedness (tree t1, tree t2) +c_decl_uninit (tree t) { - enum tree_code c1 = TREE_CODE (t1), c2 = TREE_CODE (t2); - - gcc_assert ((c1 == INTEGER_TYPE || c1 == REAL_TYPE) - && (c2 == INTEGER_TYPE || c2 == REAL_TYPE)); + /* int x = x; is GCC extension to turn off this warning, only if warn_init_self is zero. */ + if (DECL_INITIAL (t) == t) + return warn_init_self ? true : false; - /* Equality works here because c_common_signed_type uses - TYPE_MAIN_VARIANT. */ - return lang_hooks.types.signed_type (t1) - == lang_hooks.types.signed_type (t2); + /* Walk the trees looking for the variable itself. */ + if (walk_tree_without_duplicates (&DECL_INITIAL (t), c_decl_uninit_1, t)) + return true; + return false; } -/* Check for missing format attributes on function pointers. LTYPE is - the new type or left-hand side type. RTYPE is the old type or - right-hand side type. Returns TRUE if LTYPE is missing the desired - attribute. */ +/* Issue the error given by MSGID, indicating that it occurred before + TOKEN, which had the associated VALUE. */ -bool -check_missing_format_attribute (tree ltype, tree rtype) +void +c_parse_error (const char *msgid, enum cpp_ttype token, tree value) { - tree const ttr = TREE_TYPE (rtype), ttl = TREE_TYPE (ltype); - tree ra; + const char *string = _(msgid); - for (ra = TYPE_ATTRIBUTES (ttr); ra; ra = TREE_CHAIN (ra)) - if (is_attribute_p ("format", TREE_PURPOSE (ra))) - break; - if (ra) + if (token == CPP_EOF) + error ("%s at end of input", string); + else if (token == CPP_CHAR || token == CPP_WCHAR) { - tree la; - for (la = TYPE_ATTRIBUTES (ttl); la; la = TREE_CHAIN (la)) - if (is_attribute_p ("format", TREE_PURPOSE (la))) - break; - return !la; + unsigned int val = TREE_INT_CST_LOW (value); + const char *const ell = (token == CPP_CHAR) ? "" : "L"; + if (val <= UCHAR_MAX && ISGRAPH (val)) + error ("%s before %s'%c'", string, ell, val); + else + error ("%s before %s'\\x%x'", string, ell, val); } + else if (token == CPP_STRING + || token == CPP_WSTRING) + error ("%s before string constant", string); + else if (token == CPP_NUMBER) + error ("%s before numeric constant", string); + else if (token == CPP_NAME) + error ("%s before \"%s\"", string, IDENTIFIER_POINTER (value)); + else if (token < N_TTYPES) + error ("%s before '%s' token", string, cpp_type2name (token)); else - return false; + error ("%s", string); } -/* Subscripting with type char is likely to lose on a machine where - chars are signed. So warn on any machine, but optionally. Don't - warn for unsigned char since that type is safe. Don't warn for - signed char because anyone who uses that must have done so - deliberately. Furthermore, we reduce the false positive load by - warning only for non-constant value of type char. */ - -void -warn_array_subscript_with_type_char (tree index) -{ - if (TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node - && TREE_CODE (index) != INTEGER_CST) - warning (OPT_Wchar_subscripts, "array subscript has type %<char%>"); -} - - #include "gt-c-common.h" diff --git a/contrib/gcc/c-common.h b/contrib/gcc/c-common.h index 633990a..3466bff 100644 --- a/contrib/gcc/c-common.h +++ b/contrib/gcc/c-common.h @@ -1,6 +1,6 @@ /* Definitions for c-common.c. Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #ifndef GCC_C_COMMON_H #define GCC_C_COMMON_H @@ -27,14 +27,21 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "ggc.h" /* Usage of TREE_LANG_FLAG_?: - 0: TREE_NEGATED_INT (in INTEGER_CST). + 0: COMPOUND_STMT_NO_SCOPE (in COMPOUND_STMT). + TREE_NEGATED_INT (in INTEGER_CST). IDENTIFIER_MARKED (used by search routines). + SCOPE_BEGIN_P (in SCOPE_STMT) DECL_PRETTY_FUNCTION_P (in VAR_DECL) + NEW_FOR_SCOPE_P (in FOR_STMT) + ASM_INPUT_P (in ASM_STMT) + STMT_EXPR_NO_SCOPE (in STMT_EXPR) 1: C_DECLARED_LABEL_FLAG (in LABEL_DECL) - STATEMENT_LIST_STMT_EXPR (in STATEMENT_LIST) - 2: unused - 3: STATEMENT_LIST_HAS_LABEL (in STATEMENT_LIST) - 4: unused + STMT_IS_FULL_EXPR_P (in _STMT) + 2: STMT_LINENO_FOR_FN_P (in _STMT) + 3: SCOPE_NO_CLEANUPS_P (in SCOPE_STMT) + COMPOUND_STMT_BODY_BLOCK (in COMPOUND_STMT) + STMT_EXPR_WARN_UNUSED_RESULT (in STMT_EXPR) + 4: SCOPE_PARTIAL_P (in SCOPE_STMT) */ /* Reserved identifiers. This is the union of all the keywords for C, @@ -70,9 +77,8 @@ enum rid /* C extensions */ RID_ASM, RID_TYPEOF, RID_ALIGNOF, RID_ATTRIBUTE, RID_VA_ARG, - RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, - RID_TYPES_COMPATIBLE_P, - RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, + RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_PTRBASE, + RID_PTREXTENT, RID_PTRVALUE, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P, /* Too many ways of getting the name of a function as a string */ RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME, @@ -82,19 +88,19 @@ enum rid RID_PUBLIC, RID_PRIVATE, RID_PROTECTED, RID_TEMPLATE, RID_NULL, RID_CATCH, RID_DELETE, RID_FALSE, RID_NAMESPACE, - RID_NEW, RID_OFFSETOF, RID_OPERATOR, - RID_THIS, RID_THROW, RID_TRUE, - RID_TRY, RID_TYPENAME, RID_TYPEID, + RID_NEW, RID_OFFSETOF, RID_OPERATOR, + RID_THIS, RID_THROW, RID_TRUE, + RID_TRY, RID_TYPENAME, RID_TYPEID, RID_USING, /* casts */ RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, /* Objective-C */ - RID_AT_ENCODE, RID_AT_END, + RID_ID, RID_AT_ENCODE, RID_AT_END, RID_AT_CLASS, RID_AT_ALIAS, RID_AT_DEFS, RID_AT_PRIVATE, RID_AT_PROTECTED, RID_AT_PUBLIC, - RID_AT_PROTOCOL, RID_AT_SELECTOR, + RID_AT_PROTOCOL, RID_AT_SELECTOR, RID_AT_THROW, RID_AT_TRY, RID_AT_CATCH, RID_AT_FINALLY, RID_AT_SYNCHRONIZED, RID_AT_INTERFACE, @@ -112,16 +118,16 @@ enum rid }; #define OBJC_IS_AT_KEYWORD(rid) \ - ((unsigned int) (rid) >= (unsigned int) RID_FIRST_AT && \ - (unsigned int) (rid) <= (unsigned int) RID_LAST_AT) + ((unsigned int)(rid) >= (unsigned int)RID_FIRST_AT && \ + (unsigned int)(rid) <= (unsigned int)RID_LAST_AT) #define OBJC_IS_PQ_KEYWORD(rid) \ - ((unsigned int) (rid) >= (unsigned int) RID_FIRST_PQ && \ - (unsigned int) (rid) <= (unsigned int) RID_LAST_PQ) + ((unsigned int)(rid) >= (unsigned int)RID_FIRST_PQ && \ + (unsigned int)(rid) <= (unsigned int)RID_LAST_PQ) /* The elements of `ridpointers' are identifier nodes for the reserved type names and storage classes. It is indexed by a RID_... value. */ -extern GTY ((length ("(int) RID_MAX"))) tree *ridpointers; +extern GTY ((length ("(int)RID_MAX"))) tree *ridpointers; /* Standard named or nameless data types of the C compiler. */ @@ -151,16 +157,19 @@ enum c_tree_index CTI_DEFAULT_FUNCTION_TYPE, + CTI_G77_INTEGER_TYPE, + CTI_G77_UINTEGER_TYPE, + CTI_G77_LONGINT_TYPE, + CTI_G77_ULONGINT_TYPE, + /* These are not types, but we have to look them up all the time. */ CTI_FUNCTION_NAME_DECL, CTI_PRETTY_FUNCTION_NAME_DECL, CTI_C99_FUNCTION_NAME_DECL, CTI_SAVED_FUNCTION_NAME_DECLS, - + CTI_VOID_ZERO, - CTI_NULL, - CTI_MAX }; @@ -197,6 +206,12 @@ struct c_common_identifier GTY(()) #define default_function_type c_global_trees[CTI_DEFAULT_FUNCTION_TYPE] +/* g77 integer types, which which must be kept in sync with f/com.h */ +#define g77_integer_type_node c_global_trees[CTI_G77_INTEGER_TYPE] +#define g77_uinteger_type_node c_global_trees[CTI_G77_UINTEGER_TYPE] +#define g77_longint_type_node c_global_trees[CTI_G77_LONGINT_TYPE] +#define g77_ulongint_type_node c_global_trees[CTI_G77_ULONGINT_TYPE] + #define function_name_decl_node c_global_trees[CTI_FUNCTION_NAME_DECL] #define pretty_function_name_decl_node c_global_trees[CTI_PRETTY_FUNCTION_NAME_DECL] #define c99_function_name_decl_node c_global_trees[CTI_C99_FUNCTION_NAME_DECL] @@ -205,9 +220,6 @@ struct c_common_identifier GTY(()) /* A node for `((void) 0)'. */ #define void_zero_node c_global_trees[CTI_VOID_ZERO] -/* The node for C++ `__null'. */ -#define null_node c_global_trees[CTI_NULL] - extern GTY(()) tree c_global_trees[CTI_MAX]; /* In a RECORD_TYPE, a sorted array of the fields of the type, not a @@ -222,6 +234,10 @@ struct sorted_fields_type GTY(()) These may be shadowed, and may be referenced from nested functions. */ #define C_DECLARED_LABEL_FLAG(label) TREE_LANG_FLAG_1 (label) +/* Flag strings given by __FUNCTION__ and __PRETTY_FUNCTION__ for a + warning if they undergo concatenation. */ +#define C_ARTIFICIAL_STRING_P(NODE) TREE_LANG_FLAG_0 (NODE) + typedef enum c_language_kind { clk_c = 0, /* C90, C94 or C99 */ @@ -241,9 +257,13 @@ extern c_language_kind c_language; /* Information about a statement tree. */ struct stmt_tree_s GTY(()) { - /* The current statement list being collected. */ - tree x_cur_stmt_list; - + /* The last statement added to the tree. */ + tree x_last_stmt; + /* The type of the last expression statement. (This information is + needed to implement the statement-expression extension.) */ + tree x_last_expr_type; + /* The last filename we recorded. */ + const char *x_last_expr_filename; /* In C++, Nonzero if we should treat statements as full expressions. In particular, this variable is no-zero if at the end of a statement we should destroy any temporaries created @@ -270,42 +290,64 @@ struct c_language_function GTY(()) { /* While we are parsing the function, this contains information about the statement-tree that we are building. */ struct stmt_tree_s x_stmt_tree; + /* The stack of SCOPE_STMTs for the current function. */ + tree x_scope_stmt_stack; }; -/* When building a statement-tree, this is the current statement list - being collected. It's TREE_CHAIN is a back-pointer to the previous - statement list. */ +/* When building a statement-tree, this is the last statement added to + the tree. */ + +#define last_tree (current_stmt_tree ()->x_last_stmt) + +/* The type of the last expression-statement we have seen. */ + +#define last_expr_type (current_stmt_tree ()->x_last_expr_type) -#define cur_stmt_list (current_stmt_tree ()->x_cur_stmt_list) +/* The name of the last file we have seen. */ + +#define last_expr_filename (current_stmt_tree ()->x_last_expr_filename) + +/* LAST_TREE contains the last statement parsed. These are chained + together through the TREE_CHAIN field, but often need to be + re-organized since the parse is performed bottom-up. This macro + makes LAST_TREE the indicated SUBSTMT of STMT. */ + +#define RECHAIN_STMTS(stmt, substmt) \ + do { \ + substmt = TREE_CHAIN (stmt); \ + TREE_CHAIN (stmt) = NULL_TREE; \ + last_tree = stmt; \ + } while (0) /* Language-specific hooks. */ +extern void (*lang_expand_stmt) (tree); +extern void (*lang_expand_decl_stmt) (tree); +extern void (*lang_expand_function_end) (void); + /* Callback that determines if it's ok for a function to have no noreturn attribute. */ extern int (*lang_missing_noreturn_ok_p) (tree); -/* If non-NULL, this function is called after a precompile header file - is loaded. */ -extern void (*lang_post_pch_load) (void); - -extern void push_file_scope (void); -extern void pop_file_scope (void); +extern int yyparse (void); extern stmt_tree current_stmt_tree (void); -extern tree push_stmt_list (void); -extern tree pop_stmt_list (tree); +extern tree *current_scope_stmt_stack (void); +extern void begin_stmt_tree (tree *); extern tree add_stmt (tree); -extern void push_cleanup (tree, tree, bool); -extern tree pushdecl_top_level (tree); -extern tree pushdecl (tree); -extern tree build_modify_expr (tree, enum tree_code, tree); -extern tree build_indirect_ref (tree, const char *); +extern void add_decl_stmt (tree); +extern tree add_scope_stmt (int, int); +extern void finish_stmt_tree (tree *); -extern int c_expand_decl (tree); +extern tree walk_stmt_tree (tree *, walk_tree_fn, void *); +extern void prep_stmt (tree); +extern void expand_stmt (tree); +extern tree c_begin_if_stmt (void); +extern tree c_begin_while_stmt (void); +extern void c_finish_while_stmt_cond (tree, tree); extern int field_decl_cmp (const void *, const void *); -extern void resort_sorted_fields (void *, void *, gt_pointer_operator, - void *); -extern bool has_c_linkage (tree decl); +extern void resort_sorted_fields (void *, void *, gt_pointer_operator, + void *); /* Switches common to the C front ends. */ @@ -322,9 +364,6 @@ extern int flag_nil_receivers; @try, etc.) in source code. */ extern int flag_objc_exceptions; -/* Nonzero means that we generate NeXT setjmp based exceptions. */ -extern int flag_objc_sjlj_exceptions; - /* Nonzero means that code generation will be altered to support "zero-link" execution. This currently affects ObjC only, but may affect other languages in the future. */ @@ -353,10 +392,6 @@ extern char flag_dump_macros; extern char flag_dump_includes; -/* Nonzero means process PCH files while preprocessing. */ - -extern bool flag_pch_preprocess; - /* The file name to which we should write a precompiled header, or NULL if no header will be written in this compile. */ @@ -404,20 +439,107 @@ extern int flag_const_strings; /* Nonzero means to treat bitfields as signed unless they say `unsigned'. */ extern int flag_signed_bitfields; +extern int explicit_flag_signed_bitfields; + +/* Nonzero means warn about pointer casts that can drop a type qualifier + from the pointer target type. */ + +extern int warn_cast_qual; + +/* Warn about functions which might be candidates for format attributes. */ + +extern int warn_missing_format_attribute; + +/* Nonzero means do not warn that K&R style main() is not a function prototype. */ +extern int flag_bsd_no_warn_kr_main; + +/* Nonzero means warn about sizeof(function) or addition/subtraction + of function pointers. */ + +extern int warn_pointer_arith; + +/* Nonzero means warn for any global function def + without separate previous prototype decl. */ + +extern int warn_missing_prototypes; + +/* Warn if adding () is suggested. */ + +extern int warn_parentheses; + +/* Warn if initializer is not completely bracketed. */ + +extern int warn_missing_braces; + +/* Warn about comparison of signed and unsigned values. + If -1, neither -Wsign-compare nor -Wno-sign-compare has been specified. */ + +extern int warn_sign_compare; + +/* Nonzero means warn about usage of long long when `-pedantic'. */ + +extern int warn_long_long; + +/* Nonzero means warn about deprecated conversion from string constant to + `char *'. */ + +extern int warn_write_strings; -/* Warn about #pragma directives that are not recognized. */ +/* Nonzero means warn about multiple (redundant) decls for the same single + variable or function. */ -extern int warn_unknown_pragmas; /* Tri state variable. */ +extern int warn_redundant_decls; + +/* Warn about testing equality of floating point numbers. */ + +extern int warn_float_equal; + +/* Warn about a subscript that has type char. */ + +extern int warn_char_subscripts; + +/* Warn if a type conversion is done that might have confusing results. */ + +extern int warn_conversion; + +/* Warn about #pragma directives that are not recognized. */ + +extern int warn_unknown_pragmas; /* Tri state variable. */ /* Warn about format/argument anomalies in calls to formatted I/O functions (*printf, *scanf, strftime, strfmon, etc.). */ extern int warn_format; +/* Warn about Y2K problems with strftime formats. */ + +extern int warn_format_y2k; + +/* Warn about excess arguments to formats. */ + +extern int warn_format_extra_args; + +/* Warn about zero-length formats. */ + +extern int warn_format_zero_length; + +/* Warn about non-literal format arguments. */ + +extern int warn_format_nonliteral; + +/* Warn about possible security problems with calls to format functions. */ + +extern int warn_format_security; + /* C/ObjC language option variables. */ +/* Nonzero means message about use of implicit function declarations; + 1 means warning; 2 means error. */ + +extern int mesg_implicit_function_declaration; + /* Nonzero means allow type mismatches in conditional expressions; just make their values `void'. */ @@ -431,14 +553,76 @@ extern int flag_isoc94; extern int flag_isoc99; +/* Nonzero means allow the BSD kernel printf enhancments. */ + +extern int flag_bsd_format; + /* Nonzero means that we have builtin functions, and main is an int. */ extern int flag_hosted; +/* Nonzero means warn when casting a function call to a type that does + not match the return type (e.g. (float)sqrt() or (anything*)malloc() + when there is no previous declaration of sqrt or malloc. */ + +extern int warn_bad_function_cast; + +/* Warn about traditional constructs whose meanings changed in ANSI C. */ + +extern int warn_traditional; + +/* Nonzero means warn for a declaration found after a statement. */ + +extern int warn_declaration_after_statement; + +/* Nonzero means warn for non-prototype function decls + or non-prototyped defs without previous prototype. */ + +extern int warn_strict_prototypes; + +/* Nonzero means warn for any global function def + without separate previous decl. */ + +extern int warn_missing_declarations; + +/* Nonzero means warn about extern declarations of objects not at + file-scope level and about *all* declarations of functions (whether + extern or static) not at file-scope level. Note that we exclude + implicit function declarations. To get warnings about those, use + -Wimplicit. */ + +extern int warn_nested_externs; + /* Warn if main is suspicious. */ extern int warn_main; +/* Nonzero means warn about possible violations of sequence point rules. */ + +extern int warn_sequence_point; + +/* Nonzero means warn about uninitialized variable when it is initialized with itself. + For example: int i = i;, GCC will not warn about this when warn_init_self is nonzero. */ + +extern int warn_init_self; + + +/* Nonzero means to warn about compile-time division by zero. */ +extern int warn_div_by_zero; + +/* Nonzero means warn about use of implicit int. */ + +extern int warn_implicit_int; + +/* Warn about NULL being passed to argument slots marked as requiring + non-NULL. */ + +extern int warn_nonnull; + +/* Warn about old-style parameter declaration. */ + +extern int warn_old_style_definition; + /* ObjC language option variables. */ @@ -448,6 +632,10 @@ extern int warn_main; extern int flag_gen_declaration; +/* Generate code for GNU or NeXT runtime environment. */ + +extern int flag_next_runtime; + /* Tells the compiler that this is a special run. Do not perform any compiling, instead we are to test some platform dependent features and output a C header file with appropriate definitions. */ @@ -458,6 +646,25 @@ extern int print_struct_values; extern const char *constant_string_class_name; +/* Warn if multiple methods are seen for the same selector, but with + different argument types. Performs the check on the whole selector + table at the end of compilation. */ + +extern int warn_selector; + +/* Warn if a @selector() is found, and no method with that selector + has been previously declared. The check is done on each + @selector() as soon as it is found - so it warns about forward + declarations. */ + +extern int warn_undeclared_selector; + +/* Warn if methods required by a protocol are not implemented in the + class adopting it. When turned off, methods inherited to that + class are also considered implemented. */ + +extern int warn_protocol; + /* C++ language option variables. */ @@ -548,11 +755,6 @@ extern int flag_working_directory; extern int flag_use_cxa_atexit; -/* Nonzero to use __cxa_get_exception_ptr in the C++ exception-handling - logic. */ - -extern int flag_use_cxa_get_exception_ptr; - /* Nonzero means make the default pedwarns warnings instead of errors. The value of this flag is ignored if -pedantic is specified. */ @@ -565,20 +767,69 @@ extern int flag_permissive; extern int flag_enforce_eh_specs; -/* Nonzero (the default) means to generate thread-safe code for - initializing local statics. */ +/* Nonzero means warn about things that will change when compiling + with an ABI-compliant compiler. */ + +extern int warn_abi; -extern int flag_threadsafe_statics; +/* Nonzero means warn about invalid uses of offsetof. */ + +extern int warn_invalid_offsetof; /* Nonzero means warn about implicit declarations. */ extern int warn_implicit; -/* Warn about using __null (as NULL in C++) as sentinel. For code compiled - with GCC this doesn't matter as __null is guaranteed to have the right - size. */ +/* Nonzero means warn when all ctors or dtors are private, and the class + has no friends. */ + +extern int warn_ctor_dtor_privacy; + +/* Nonzero means warn in function declared in derived class has the + same name as a virtual in the base class, but fails to match the + type signature of any virtual function in the base class. */ + +extern int warn_overloaded_virtual; + +/* Nonzero means warn when declaring a class that has a non virtual + destructor, when it really ought to have a virtual one. */ + +extern int warn_nonvdtor; + +/* Nonzero means warn when the compiler will reorder code. */ + +extern int warn_reorder; + +/* Nonzero means warn when synthesis behavior differs from Cfront's. */ + +extern int warn_synth; + +/* Nonzero means warn when we convert a pointer to member function + into a pointer to (void or function). */ + +extern int warn_pmf2ptr; + +/* Nonzero means warn about violation of some Effective C++ style rules. */ + +extern int warn_ecpp; + +/* Nonzero means warn where overload resolution chooses a promotion from + unsigned to signed over a conversion to an unsigned of the same size. */ + +extern int warn_sign_promo; + +/* Nonzero means warn when an old-style cast is used. */ + +extern int warn_old_style_cast; + +/* Nonzero means warn when non-templatized friend functions are + declared within a template */ -extern int warn_strict_null_sentinel; +extern int warn_nontemplate_friend; + +/* Nonzero means complain about deprecated features. */ + +extern int warn_deprecated; /* Maximum template instantiation depth. This limit is rather arbitrary, but it exists to limit the time it takes to notice @@ -607,6 +858,10 @@ extern int skip_evaluation; #define C_TYPE_OBJECT_OR_INCOMPLETE_P(type) \ (!C_TYPE_FUNCTION_P (type)) +/* Record in each node resulting from a binary operator + what operator was specified for it. */ +#define C_EXP_ORIGINAL_CODE(exp) ((enum tree_code) TREE_COMPLEXITY (exp)) + /* Attribute table common to the C front ends. */ extern const struct attribute_spec c_common_attribute_table[]; extern const struct attribute_spec c_common_format_attribute_table[]; @@ -626,13 +881,13 @@ extern void finish_fname_decls (void); extern const char *fname_as_string (int); extern tree fname_decl (unsigned, tree); -extern void check_function_arguments (tree, tree, tree); +extern void check_function_arguments (tree, tree); extern void check_function_arguments_recurse (void (*) (void *, tree, unsigned HOST_WIDE_INT), void *, tree, unsigned HOST_WIDE_INT); -extern void check_function_format (tree, tree); +extern void check_function_format (int *, tree, tree); extern void set_Wformat (int); extern tree handle_format_attribute (tree *, tree, tree, int, bool *); extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); @@ -643,26 +898,36 @@ extern tree c_common_type_for_size (unsigned int, int); extern tree c_common_unsigned_type (tree); extern tree c_common_signed_type (tree); extern tree c_common_signed_or_unsigned_type (int, tree); -extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int); extern tree c_common_truthvalue_conversion (tree); extern void c_apply_type_quals_to_decl (int, tree); -extern tree c_sizeof_or_alignof_type (tree, bool, int); +extern tree c_sizeof_or_alignof_type (tree, enum tree_code, int); extern tree c_alignof_expr (tree); /* Print an error message for invalid operands to arith operation CODE. NOP_EXPR is used as a special case (see truthvalue_conversion). */ extern void binary_op_error (enum tree_code); +#define my_friendly_assert(EXP, N) (void) \ + (((EXP) == 0) ? (fancy_abort (__FILE__, __LINE__, __FUNCTION__), 0) : 0) + +extern tree c_expand_expr_stmt (tree); +extern void c_expand_start_cond (tree, int, tree); +extern void c_finish_then (void); +extern void c_expand_start_else (void); +extern void c_finish_else (void); +extern void c_expand_end_cond (void); +/* Validate the expression after `case' and apply default promotions. */ +extern tree check_case_value (tree); extern tree fix_string_type (tree); struct varray_head_tag; extern void constant_expression_warning (tree); -extern void strict_aliasing_warning(tree, tree, tree); -extern void empty_body_warning (tree, tree); extern tree convert_and_check (tree, tree); extern void overflow_warning (tree); -extern bool c_determine_visibility (tree); -extern bool same_scalar_type_ignoring_signedness (tree, tree); +extern void unsigned_conversion_warning (tree, tree); -#define c_sizeof(T) c_sizeof_or_alignof_type (T, true, 1) -#define c_alignof(T) c_sizeof_or_alignof_type (T, false, 1) +/* Read the rest of the current #-directive line. */ +extern char *get_directive_line (void); +#define GET_DIRECTIVE_LINE() get_directive_line () +#define c_sizeof(T) c_sizeof_or_alignof_type (T, SIZEOF_EXPR, 1) +#define c_alignof(T) c_sizeof_or_alignof_type (T, ALIGNOF_EXPR, 1) /* Subroutine of build_binary_op, used for comparison operations. See if the operands have both been converted from subword integer types @@ -679,12 +944,8 @@ extern tree c_build_qualified_type (tree, int); frontends. */ extern void c_common_nodes_and_builtins (void); -extern void set_builtin_user_assembler_name (tree decl, const char *asmspec); - extern void disable_builtin_function (const char *); -extern void set_compound_literal_name (tree decl); - extern tree build_va_arg (tree, tree); extern unsigned int c_common_init_options (unsigned int, const char **); @@ -698,30 +959,190 @@ extern bool c_promoting_integer_type_p (tree); extern int self_promoting_args_p (tree); extern tree strip_array_types (tree); extern tree strip_pointer_operator (tree); -extern HOST_WIDE_INT c_common_to_target_charset (HOST_WIDE_INT); +/* This function resets the parsers' state in preparation for parsing + a new file. */ +extern void c_reset_state (void); /* This is the basic parsing function. */ extern void c_parse_file (void); /* This is misnamed, it actually performs end-of-compilation processing. */ extern void finish_file (void); - /* These macros provide convenient access to the various _STMT nodes. */ -/* Nonzero if a given STATEMENT_LIST represents the outermost binding - if a statement expression. */ -#define STATEMENT_LIST_STMT_EXPR(NODE) \ - TREE_LANG_FLAG_1 (STATEMENT_LIST_CHECK (NODE)) - -/* Nonzero if a label has been added to the statement list. */ -#define STATEMENT_LIST_HAS_LABEL(NODE) \ - TREE_LANG_FLAG_3 (STATEMENT_LIST_CHECK (NODE)) +/* Nonzero if this statement should be considered a full-expression, + i.e., if temporaries created during this statement should have + their destructors run at the end of this statement. (In C, this + will always be false, since there are no destructors.) */ +#define STMT_IS_FULL_EXPR_P(NODE) TREE_LANG_FLAG_1 ((NODE)) + +/* IF_STMT accessors. These give access to the condition of the if + statement, the then block of the if statement, and the else block + of the if statement if it exists. */ +#define IF_COND(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 0) +#define THEN_CLAUSE(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 1) +#define ELSE_CLAUSE(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 2) + +/* WHILE_STMT accessors. These give access to the condition of the + while statement and the body of the while statement, respectively. */ +#define WHILE_COND(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 0) +#define WHILE_BODY(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 1) + +/* DO_STMT accessors. These give access to the condition of the do + statement and the body of the do statement, respectively. */ +#define DO_COND(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 0) +#define DO_BODY(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 1) + +/* RETURN_STMT accessors. These give the expression associated with a + return statement, and whether it should be ignored when expanding + (as opposed to inlining). */ +#define RETURN_STMT_EXPR(NODE) TREE_OPERAND (RETURN_STMT_CHECK (NODE), 0) + +/* EXPR_STMT accessor. This gives the expression associated with an + expression statement. */ +#define EXPR_STMT_EXPR(NODE) TREE_OPERAND (EXPR_STMT_CHECK (NODE), 0) + +/* FOR_STMT accessors. These give access to the init statement, + condition, update expression, and body of the for statement, + respectively. */ +#define FOR_INIT_STMT(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 0) +#define FOR_COND(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 1) +#define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2) +#define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3) + +/* SWITCH_STMT accessors. These give access to the condition, body and + original condition type (before any compiler conversions) + of the switch statement, respectively. */ +#define SWITCH_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0) +#define SWITCH_BODY(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1) +#define SWITCH_TYPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2) + +/* CASE_LABEL accessors. These give access to the high and low values + of a case label, respectively. */ +#define CASE_LOW(NODE) TREE_OPERAND (CASE_LABEL_CHECK (NODE), 0) +#define CASE_HIGH(NODE) TREE_OPERAND (CASE_LABEL_CHECK (NODE), 1) +#define CASE_LABEL_DECL(NODE) TREE_OPERAND (CASE_LABEL_CHECK (NODE), 2) + +/* GOTO_STMT accessor. This gives access to the label associated with + a goto statement. */ +#define GOTO_DESTINATION(NODE) TREE_OPERAND (GOTO_STMT_CHECK (NODE), 0) +/* True for goto created artificially by the compiler. */ +#define GOTO_FAKE_P(NODE) (TREE_LANG_FLAG_0 (GOTO_STMT_CHECK (NODE))) + +/* COMPOUND_STMT accessor. This gives access to the TREE_LIST of + statements associated with a compound statement. The result is the + first statement in the list. Succeeding nodes can be accessed by + calling TREE_CHAIN on a node in the list. */ +#define COMPOUND_BODY(NODE) TREE_OPERAND (COMPOUND_STMT_CHECK (NODE), 0) + +/* ASM_STMT accessors. ASM_STRING returns a STRING_CST for the + instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and + ASM_CLOBBERS represent the outputs, inputs, and clobbers for the + statement. */ +#define ASM_CV_QUAL(NODE) TREE_OPERAND (ASM_STMT_CHECK (NODE), 0) +#define ASM_STRING(NODE) TREE_OPERAND (ASM_STMT_CHECK (NODE), 1) +#define ASM_OUTPUTS(NODE) TREE_OPERAND (ASM_STMT_CHECK (NODE), 2) +#define ASM_INPUTS(NODE) TREE_OPERAND (ASM_STMT_CHECK (NODE), 3) +#define ASM_CLOBBERS(NODE) TREE_OPERAND (ASM_STMT_CHECK (NODE), 4) + +/* DECL_STMT accessor. This gives access to the DECL associated with + the given declaration statement. */ +#define DECL_STMT_DECL(NODE) TREE_OPERAND (DECL_STMT_CHECK (NODE), 0) + +/* STMT_EXPR accessor. */ +#define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0) + +/* Nonzero if this statement-expression does not have an associated scope. */ +#define STMT_EXPR_NO_SCOPE(NODE) \ + TREE_LANG_FLAG_0 (STMT_EXPR_CHECK (NODE)) + +/* Nonzero if this statement-expression should cause warning if its result + is not used. */ +#define STMT_EXPR_WARN_UNUSED_RESULT(NODE) \ + TREE_LANG_FLAG_3 (STMT_EXPR_CHECK (NODE)) + +/* LABEL_STMT accessor. This gives access to the label associated with + the given label statement. */ +#define LABEL_STMT_LABEL(NODE) TREE_OPERAND (LABEL_STMT_CHECK (NODE), 0) /* COMPOUND_LITERAL_EXPR accessors. */ #define COMPOUND_LITERAL_EXPR_DECL_STMT(NODE) \ TREE_OPERAND (COMPOUND_LITERAL_EXPR_CHECK (NODE), 0) #define COMPOUND_LITERAL_EXPR_DECL(NODE) \ - DECL_EXPR_DECL (COMPOUND_LITERAL_EXPR_DECL_STMT (NODE)) + DECL_STMT_DECL (COMPOUND_LITERAL_EXPR_DECL_STMT (NODE)) + +/* Nonzero if this SCOPE_STMT is for the beginning of a scope. */ +#define SCOPE_BEGIN_P(NODE) \ + (TREE_LANG_FLAG_0 (SCOPE_STMT_CHECK (NODE))) + +/* Nonzero if this SCOPE_STMT is for the end of a scope. */ +#define SCOPE_END_P(NODE) \ + (!SCOPE_BEGIN_P (SCOPE_STMT_CHECK (NODE))) + +/* The BLOCK containing the declarations contained in this scope. */ +#define SCOPE_STMT_BLOCK(NODE) \ + (TREE_OPERAND (SCOPE_STMT_CHECK (NODE), 0)) + +/* Nonzero for a SCOPE_STMT if there were no variables in this scope. */ +#define SCOPE_NULLIFIED_P(NODE) \ + (SCOPE_STMT_BLOCK ((NODE)) == NULL_TREE) + +/* Nonzero for a SCOPE_STMT which represents a lexical scope, but + which should be treated as non-existent from the point of view of + running cleanup actions. */ +#define SCOPE_NO_CLEANUPS_P(NODE) \ + (TREE_LANG_FLAG_3 (SCOPE_STMT_CHECK (NODE))) + +/* Nonzero for a SCOPE_STMT if this statement is for a partial scope. + For example, in: + + S s; + l: + S s2; + goto l; + + there is (implicitly) a new scope after `l', even though there are + no curly braces. In particular, when we hit the goto, we must + destroy s2 and then re-construct it. For the implicit scope, + SCOPE_PARTIAL_P will be set. */ +#define SCOPE_PARTIAL_P(NODE) \ + (TREE_LANG_FLAG_4 (SCOPE_STMT_CHECK (NODE))) + +/* Nonzero for an ASM_STMT if the assembly statement is volatile. */ +#define ASM_VOLATILE_P(NODE) \ + (ASM_CV_QUAL (ASM_STMT_CHECK (NODE)) != NULL_TREE) + +/* The VAR_DECL to clean up in a CLEANUP_STMT. */ +#define CLEANUP_DECL(NODE) \ + TREE_OPERAND (CLEANUP_STMT_CHECK (NODE), 0) +/* The cleanup to run in a CLEANUP_STMT. */ +#define CLEANUP_EXPR(NODE) \ + TREE_OPERAND (CLEANUP_STMT_CHECK (NODE), 1) + +/* The filename we are changing to as of this FILE_STMT. */ +#define FILE_STMT_FILENAME_NODE(NODE) \ + (TREE_OPERAND (FILE_STMT_CHECK (NODE), 0)) +#define FILE_STMT_FILENAME(NODE) \ + (IDENTIFIER_POINTER (FILE_STMT_FILENAME_NODE (NODE))) + +/* The line-number at which a statement began. But if + STMT_LINENO_FOR_FN_P does holds, then this macro gives the + line number for the end of the current function instead. */ +#define STMT_LINENO(NODE) \ + (TREE_COMPLEXITY ((NODE))) + +/* If nonzero, the STMT_LINENO for NODE is the line at which the + function ended. */ +#define STMT_LINENO_FOR_FN_P(NODE) \ + (TREE_LANG_FLAG_2 ((NODE))) + +/* Nonzero if we want the new ISO rules for pushing a new scope for `for' + initialization variables. */ +#define NEW_FOR_SCOPE_P(NODE) (TREE_LANG_FLAG_0 (NODE)) + +/* Nonzero if we want to create an ASM_INPUT instead of an + ASM_OPERAND with no operands. */ +#define ASM_INPUT_P(NODE) (TREE_LANG_FLAG_0 (NODE)) #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM, @@ -733,6 +1154,47 @@ enum c_tree_code { #undef DEFTREECODE +#define c_common_stmt_codes \ + CLEANUP_STMT, EXPR_STMT, COMPOUND_STMT, \ + DECL_STMT, IF_STMT, FOR_STMT, \ + WHILE_STMT, DO_STMT, RETURN_STMT, \ + BREAK_STMT, CONTINUE_STMT, SCOPE_STMT, \ + SWITCH_STMT, GOTO_STMT, LABEL_STMT, \ + ASM_STMT, FILE_STMT, CASE_LABEL + +/* TRUE if a code represents a statement. The front end init + langhook should take care of initialization of this array. */ +extern bool statement_code_p[MAX_TREE_CODES]; + +#define STATEMENT_CODE_P(CODE) statement_code_p[(int) (CODE)] + +#define INIT_STATEMENT_CODES(STMT_CODES) \ + do { \ + unsigned int i; \ + memset (&statement_code_p, 0, sizeof (statement_code_p)); \ + for (i = 0; i < ARRAY_SIZE (STMT_CODES); i++) \ + statement_code_p[STMT_CODES[i]] = true; \ + } while (0) + +extern void genrtl_do_pushlevel (void); +extern void genrtl_goto_stmt (tree); +extern void genrtl_expr_stmt (tree); +extern void genrtl_expr_stmt_value (tree, int, int); +extern void genrtl_decl_stmt (tree); +extern void genrtl_if_stmt (tree); +extern void genrtl_while_stmt (tree); +extern void genrtl_do_stmt (tree); +extern void genrtl_return_stmt (tree); +extern void genrtl_for_stmt (tree); +extern void genrtl_break_stmt (void); +extern void genrtl_continue_stmt (void); +extern void genrtl_scope_stmt (tree); +extern void genrtl_switch_stmt (tree); +extern void genrtl_case_label (tree); +extern void genrtl_compound_stmt (tree); +extern void genrtl_asm_stmt (tree, tree, tree, tree, tree, int); +extern void genrtl_cleanup_stmt (tree); +extern int stmts_are_full_exprs_p (void); extern int anon_aggr_type_p (tree); /* For a VAR_DECL that is an anonymous union, these are the various @@ -747,21 +1209,35 @@ extern int anon_aggr_type_p (tree); #define CLEAR_DECL_C_BIT_FIELD(NODE) \ (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 0) +/* In a VAR_DECL, nonzero if the decl is a register variable with + an explicit asm specification. */ +#define DECL_C_HARD_REGISTER(DECL) DECL_LANG_FLAG_4 (VAR_DECL_CHECK (DECL)) + extern void emit_local_var (tree); +extern void make_rtl_for_local_static (tree); +extern tree expand_cond (tree); +extern tree c_expand_return (tree); extern tree do_case (tree, tree); extern tree build_stmt (enum tree_code, ...); extern tree build_case_label (tree, tree, tree); +extern tree build_continue_stmt (void); +extern tree build_break_stmt (void); +extern tree build_return_stmt (tree); + +#define COMPOUND_STMT_NO_SCOPE(NODE) TREE_LANG_FLAG_0 (NODE) + +/* Used by the C++ frontend to mark the block around the member + initializers and cleanups. */ +#define COMPOUND_STMT_BODY_BLOCK(NODE) TREE_LANG_FLAG_3 (NODE) + +extern void c_expand_asm_operands (tree, tree, tree, tree, int, location_t); /* These functions must be defined by each front-end which implements a variant of the C language. They are used in c-common.c. */ extern tree build_unary_op (enum tree_code, tree, int); extern tree build_binary_op (enum tree_code, tree, tree, int); -extern tree perform_integral_promotions (tree); - -/* These functions must be defined by each front-end which implements - a variant of the C language. They are used by port files. */ - +extern int lvalue_p (tree); extern tree default_conversion (tree); /* Given two integer or real types, return the type for their sum. @@ -769,33 +1245,38 @@ extern tree default_conversion (tree); extern tree common_type (tree, tree); +extern tree expand_tree_builtin (tree, tree, tree); + extern tree decl_constant_value (tree); /* Handle increment and decrement of boolean types. */ extern tree boolean_increment (enum tree_code, tree); -extern int case_compare (splay_tree_key, splay_tree_key); +/* Hook currently used only by the C++ front end to reset internal state + after entering or leaving a header file. */ +extern void extract_interface_info (void); -extern tree c_add_case_label (splay_tree, tree, tree, tree, tree); +extern int case_compare (splay_tree_key, splay_tree_key); -extern void c_do_switch_warnings (splay_tree, location_t, tree, tree); +extern tree c_add_case_label (splay_tree, tree, tree, tree); extern tree build_function_call (tree, tree); -extern tree resolve_overloaded_builtin (tree, tree); - extern tree finish_label_address_expr (tree); /* Same function prototype, but the C and C++ front ends have different implementations. Used in c-common.c. */ extern tree lookup_label (tree); -extern tree lookup_name (tree); extern int vector_types_convertible_p (tree t1, tree t2); extern rtx c_expand_expr (tree, rtx, enum machine_mode, int, rtx *); -extern tree c_staticp (tree); +extern int c_safe_from_p (rtx, tree); + +extern int c_staticp (tree); + +extern int c_common_unsafe_for_reeval (tree); extern void init_c_lex (void); @@ -803,21 +1284,14 @@ extern void c_cpp_builtins (cpp_reader *); /* Positive if an implicit `extern "C"' scope has just been entered; negative if such a scope has just been exited. */ -extern GTY(()) int pending_lang_change; +extern int pending_lang_change; /* Information recorded about each file examined during compilation. */ struct c_fileinfo { int time; /* Time spent in the file. */ - - /* Flags used only by C++. - INTERFACE_ONLY nonzero means that we are in an "interface" section - of the compiler. INTERFACE_UNKNOWN nonzero means we cannot trust - the value of INTERFACE_ONLY. If INTERFACE_UNKNOWN is zero and - INTERFACE_ONLY is zero, it means that we are responsible for - exporting definitions that others might need. */ - short interface_only; + short interface_only; /* Flags - used only by C++ */ short interface_unknown; }; @@ -826,114 +1300,30 @@ extern void dump_time_statistics (void); extern bool c_dump_tree (void *, tree); -extern void c_warn_unused_result (tree *); - -extern void verify_sequence_points (tree); - -extern tree fold_offsetof (tree, tree); - -/* Places where an lvalue, or modifiable lvalue, may be required. - Used to select diagnostic messages in lvalue_error and - readonly_error. */ -enum lvalue_use { - lv_assign, - lv_increment, - lv_decrement, - lv_addressof, - lv_asm -}; - -extern void lvalue_error (enum lvalue_use); - -extern int complete_array_type (tree *, tree, bool); - -extern tree builtin_type_for_size (int, bool); - -extern void warn_array_subscript_with_type_char (tree); - -/* In c-gimplify.c */ -extern void c_genericize (tree); -extern int c_gimplify_expr (tree *, tree *, tree *); -extern tree c_build_bind_expr (tree, tree); - -/* In c-pch.c */ extern void pch_init (void); extern int c_common_valid_pch (cpp_reader *pfile, const char *name, int fd); extern void c_common_read_pch (cpp_reader *pfile, const char *name, int fd, const char *orig); extern void c_common_write_pch (void); extern void c_common_no_more_pch (void); -extern void c_common_pch_pragma (cpp_reader *pfile, const char *); -extern void c_common_print_pch_checksum (FILE *f); - -/* In *-checksum.c */ -extern const unsigned char executable_checksum[16]; - extern void builtin_define_with_value (const char *, const char *, int); extern void c_stddef_cpp_builtins (void); extern void fe_file_change (const struct line_map *); +extern int c_estimate_num_insns (tree decl); +extern bool c_decl_uninit (tree t); extern void c_parse_error (const char *, enum cpp_ttype, tree); -/* Objective-C / Objective-C++ entry points. */ - -/* The following ObjC/ObjC++ functions are called by the C and/or C++ - front-ends; they all must have corresponding stubs in stub-objc.c. */ -extern tree objc_is_class_name (tree); +/* The following have been moved here from c-tree.h, since they're needed + in the ObjC++ world, too. What is more, stub-objc.c could use a few + prototypes. */ +extern tree lookup_interface (tree); +extern tree is_class_name (tree); extern tree objc_is_object_ptr (tree); extern void objc_check_decl (tree); -extern int objc_is_reserved_word (tree); -extern bool objc_compare_types (tree, tree, int, tree); -extern void objc_volatilize_decl (tree); -extern bool objc_type_quals_match (tree, tree); -extern tree objc_rewrite_function_call (tree, tree); +extern int objc_comptypes (tree, tree, int); extern tree objc_message_selector (void); -extern tree objc_lookup_ivar (tree, tree); -extern void objc_clear_super_receiver (void); -extern int objc_is_public (tree, tree); -extern tree objc_is_id (tree); -extern void objc_declare_alias (tree, tree); -extern void objc_declare_class (tree); -extern void objc_declare_protocols (tree); -extern tree objc_build_message_expr (tree); -extern tree objc_finish_message_expr (tree, tree, tree); -extern tree objc_build_selector_expr (tree); -extern tree objc_build_protocol_expr (tree); -extern tree objc_build_encode_expr (tree); -extern tree objc_build_string_object (tree); -extern tree objc_get_protocol_qualified_type (tree, tree); -extern tree objc_get_class_reference (tree); -extern tree objc_get_class_ivars (tree); -extern void objc_start_class_interface (tree, tree, tree); -extern void objc_start_category_interface (tree, tree, tree); -extern void objc_start_protocol (tree, tree); -extern void objc_continue_interface (void); -extern void objc_finish_interface (void); -extern void objc_start_class_implementation (tree, tree); -extern void objc_start_category_implementation (tree, tree); -extern void objc_continue_implementation (void); -extern void objc_finish_implementation (void); -extern void objc_set_visibility (int); -extern void objc_set_method_type (enum tree_code); -extern tree objc_build_method_signature (tree, tree, tree, bool); -extern void objc_add_method_declaration (tree); -extern void objc_start_method_definition (tree); -extern void objc_finish_method_definition (tree); -extern void objc_add_instance_variable (tree); -extern tree objc_build_keyword_decl (tree, tree, tree); -extern tree objc_build_throw_stmt (tree); -extern void objc_begin_try_stmt (location_t, tree); -extern tree objc_finish_try_stmt (void); -extern void objc_begin_catch_clause (tree); -extern void objc_finish_catch_clause (void); -extern void objc_build_finally_clause (location_t, tree); -extern tree objc_build_synchronized (location_t, tree, tree); -extern int objc_static_init_needed_p (void); -extern tree objc_generate_static_init_call (tree); -extern tree objc_generate_write_barrier (tree, enum tree_code, tree); - -/* The following are provided by the C and C++ front-ends, and called by - ObjC/ObjC++. */ -extern void *objc_get_current_scope (void); +extern tree lookup_objc_ivar (tree); +extern void *get_current_scope (void); extern void objc_mark_locals_volatile (void *); /* In c-ppoutput.c */ @@ -941,30 +1331,5 @@ extern void init_pp_output (FILE *); extern void preprocess_file (cpp_reader *); extern void pp_file_change (const struct line_map *); extern void pp_dir_change (cpp_reader *, const char *); -extern bool check_missing_format_attribute (tree, tree); - -/* In c-omp.c */ -extern tree c_finish_omp_master (tree); -extern tree c_finish_omp_critical (tree, tree); -extern tree c_finish_omp_ordered (tree); -extern void c_finish_omp_barrier (void); -extern tree c_finish_omp_atomic (enum tree_code, tree, tree); -extern void c_finish_omp_flush (void); -extern tree c_finish_omp_for (location_t, tree, tree, tree, tree, tree, tree); -extern void c_split_parallel_clauses (tree, tree *, tree *); -extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); - -/* Not in c-omp.c; provided by the front end. */ -extern bool c_omp_sharing_predetermined (tree); -extern tree c_omp_remap_decl (tree, bool); - -/* In order for the format checking to accept the C frontend - diagnostic framework extensions, you must include this file before - toplev.h, not after. The C front end formats are a subset of those - for C++, so they are the appropriate set to use in common code; - cp-tree.h overrides this for C++. */ -#ifndef GCC_DIAG_STYLE -#define GCC_DIAG_STYLE __gcc_cdiag__ -#endif #endif /* ! GCC_C_COMMON_H */ diff --git a/contrib/gcc/c-decl.c b/contrib/gcc/c-decl.c index 00b372e..af6d668 100644 --- a/contrib/gcc/c-decl.c +++ b/contrib/gcc/c-decl.c @@ -1,6 +1,6 @@ /* Process declarations and variables for C compiler. Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,10 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* $FreeBSD$ */ /* Process declarations and symbol lookup for C front end. Also constructs types; the standard scalar types at initialization, @@ -29,7 +31,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "config.h" #include "system.h" #include "coretypes.h" -#include "input.h" #include "tm.h" #include "intl.h" #include "tree.h" @@ -50,17 +51,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "timevar.h" #include "c-common.h" #include "c-pragma.h" -#include "langhooks.h" -#include "tree-mudflap.h" -#include "tree-gimple.h" -#include "diagnostic.h" -#include "tree-dump.h" #include "cgraph.h" #include "hashtab.h" #include "libfuncs.h" #include "except.h" #include "langhooks-def.h" -#include "pointer-set.h" /* In grokdeclarator, distinguish syntactic contexts of declarators. */ enum decl_context @@ -73,14 +68,11 @@ enum decl_context /* Nonzero if we have seen an invalid cross reference to a struct, union, or enum, but not yet printed the message. */ -tree pending_invalid_xref; +tree pending_invalid_xref; /* File and line to appear in the eventual error message. */ location_t pending_invalid_xref_location; -/* True means we've initialized exception handling. */ -bool c_eh_initialized_p; - /* While defining an enum type, this is 1 plus the last enumerator constant value. Note that will do not have to save this or `enum_overflow' around nested function definition since such a definition could only @@ -93,46 +85,64 @@ static tree enum_next_value; static int enum_overflow; -/* The file and line that the prototype came from if this is an - old-style definition; used for diagnostics in - store_parm_decls_oldstyle. */ +/* Parsing a function declarator leaves a list of parameter names + or a chain of parameter decls here. */ -static location_t current_function_prototype_locus; +static tree last_function_parms; + +/* ... and a chain of structure and enum types declared in the + parmlist here. */ -/* Whether this prototype was built-in. */ +static tree last_function_parm_tags; -static bool current_function_prototype_built_in; +/* ... and a chain of all non-parameter declarations (such as + CONST_DECLs from enumerations) here. */ -/* The argument type information of this prototype. */ +static tree last_function_parm_others; -static tree current_function_prototype_arg_types; +/* After parsing the declarator that starts a function definition, + `start_function' puts the list of parameter names or chain of decls here + for `store_parm_decls' to find. */ -/* The argument information structure for the function currently being - defined. */ +static tree current_function_parms; -static struct c_arg_info *current_function_arg_info; +/* Similar, for last_function_parm_tags. */ -/* The obstack on which parser and related data structures, which are - not live beyond their top-level declaration or definition, are - allocated. */ -struct obstack parser_obstack; +static tree current_function_parm_tags; + +/* And for last_function_parm_others. */ + +static tree current_function_parm_others; + +/* Similar, for the file and line that the prototype came from if this is + an old-style definition. */ + +static location_t current_function_prototype_locus; /* The current statement tree. */ static GTY(()) struct stmt_tree_s c_stmt_tree; +/* The current scope statement stack. */ + +static GTY(()) tree c_scope_stmt_stack; + /* State saving variables. */ -tree c_break_label; -tree c_cont_label; +int c_in_iteration_stmt; +int c_in_case_stmt; + +/* A list of external DECLs that appeared at block scope when there was + some other global meaning for that identifier. */ +static GTY(()) tree truly_local_externals; + +/* All the builtins; this is a subset of the entries of global_scope. */ -/* Linked list of TRANSLATION_UNIT_DECLS for the translation units - included in this invocation. Note that the current translation - unit is not included in this list. */ +static GTY(()) tree first_builtin_decl; +static GTY(()) tree last_builtin_decl; -static GTY(()) tree all_translation_units; +/* A DECL for the current file-scope context. */ -/* A list of decls to be made automatically visible in each file scope. */ -static GTY(()) tree visible_builtins; +static GTY(()) tree current_file_decl; /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ @@ -157,115 +167,10 @@ static int warn_about_return_type; /* Nonzero when starting a function declared `extern inline'. */ static int current_extern_inline; - -/* Nonzero when the current toplevel function contains a declaration - of a nested function which is never defined. */ - -static bool undef_nested_function; - -/* True means global_bindings_p should return false even if the scope stack - says we are in file scope. */ -bool c_override_global_bindings_to_false; - -/* Each c_binding structure describes one binding of an identifier to - a decl. All the decls in a scope - irrespective of namespace - are - chained together by the ->prev field, which (as the name implies) - runs in reverse order. All the decls in a given namespace bound to - a given identifier are chained by the ->shadowed field, which runs - from inner to outer scopes. - - The ->decl field usually points to a DECL node, but there are two - exceptions. In the namespace of type tags, the bound entity is a - RECORD_TYPE, UNION_TYPE, or ENUMERAL_TYPE node. If an undeclared - identifier is encountered, it is bound to error_mark_node to - suppress further errors about that identifier in the current - function. - - The ->type field stores the type of the declaration in this scope; - if NULL, the type is the type of the ->decl field. This is only of - relevance for objects with external or internal linkage which may - be redeclared in inner scopes, forming composite types that only - persist for the duration of those scopes. In the external scope, - this stores the composite of all the types declared for this - object, visible or not. The ->inner_comp field (used only at file - scope) stores whether an incomplete array type at file scope was - completed at an inner scope to an array size other than 1. - - The depth field is copied from the scope structure that holds this - decl. It is used to preserve the proper ordering of the ->shadowed - field (see bind()) and also for a handful of special-case checks. - Finally, the invisible bit is true for a decl which should be - ignored for purposes of normal name lookup, and the nested bit is - true for a decl that's been bound a second time in an inner scope; - in all such cases, the binding in the outer scope will have its - invisible bit true. */ - -struct c_binding GTY((chain_next ("%h.prev"))) -{ - tree decl; /* the decl bound */ - tree type; /* the type in this scope */ - tree id; /* the identifier it's bound to */ - struct c_binding *prev; /* the previous decl in this scope */ - struct c_binding *shadowed; /* the innermost decl shadowed by this one */ - unsigned int depth : 28; /* depth of this scope */ - BOOL_BITFIELD invisible : 1; /* normal lookup should ignore this binding */ - BOOL_BITFIELD nested : 1; /* do not set DECL_CONTEXT when popping */ - BOOL_BITFIELD inner_comp : 1; /* incomplete array completed in inner scope */ - /* one free bit */ -}; -#define B_IN_SCOPE(b1, b2) ((b1)->depth == (b2)->depth) -#define B_IN_CURRENT_SCOPE(b) ((b)->depth == current_scope->depth) -#define B_IN_FILE_SCOPE(b) ((b)->depth == 1 /*file_scope->depth*/) -#define B_IN_EXTERNAL_SCOPE(b) ((b)->depth == 0 /*external_scope->depth*/) - -#define I_SYMBOL_BINDING(node) \ - (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->symbol_binding) -#define I_SYMBOL_DECL(node) \ - (I_SYMBOL_BINDING(node) ? I_SYMBOL_BINDING(node)->decl : 0) - -#define I_TAG_BINDING(node) \ - (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->tag_binding) -#define I_TAG_DECL(node) \ - (I_TAG_BINDING(node) ? I_TAG_BINDING(node)->decl : 0) - -#define I_LABEL_BINDING(node) \ - (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->label_binding) -#define I_LABEL_DECL(node) \ - (I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0) - -/* Each C symbol points to three linked lists of c_binding structures. - These describe the values of the identifier in the three different - namespaces defined by the language. */ - -struct lang_identifier GTY(()) -{ - struct c_common_identifier common_id; - struct c_binding *symbol_binding; /* vars, funcs, constants, typedefs */ - struct c_binding *tag_binding; /* struct/union/enum tags */ - struct c_binding *label_binding; /* labels */ -}; - -/* Validate c-lang.c's assumptions. */ -extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate -[(sizeof(struct lang_identifier) == C_SIZEOF_STRUCT_LANG_IDENTIFIER) ? 1 : -1]; - -/* The resulting tree type. */ - -union lang_tree_node - GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), - chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE ? (union lang_tree_node *) TYPE_NEXT_VARIANT (&%h.generic) : (union lang_tree_node *) TREE_CHAIN (&%h.generic)"))) -{ - union tree_node GTY ((tag ("0"), - desc ("tree_node_structure (&%h)"))) - generic; - struct lang_identifier GTY ((tag ("1"))) identifier; -}; - -/* Each c_scope structure describes the complete contents of one - scope. Four scopes are distinguished specially: the innermost or - current scope, the innermost function scope, the file scope (always - the second to outermost) and the outermost or external scope. +/* Each c_scope structure describes the complete contents of one scope. + Three scopes are distinguished specially: the innermost or current + scope, the innermost function scope, and the outermost or file scope. Most declarations are recorded in the current scope. @@ -275,39 +180,20 @@ union lang_tree_node hence the 'innermost' qualifier.) Explicitly declared labels (using the __label__ extension) appear in the current scope. - Being in the file scope (current_scope == file_scope) causes + Being in the global scope (current_scope == global_scope) causes special behavior in several places below. Also, under some conditions the Objective-C front end records declarations in the - file scope even though that isn't the current scope. - - All declarations with external linkage are recorded in the external - scope, even if they aren't visible there; this models the fact that - such declarations are visible to the entire program, and (with a - bit of cleverness, see pushdecl) allows diagnosis of some violations - of C99 6.2.2p7 and 6.2.7p2: + global scope even though that isn't the current scope. - If, within the same translation unit, the same identifier appears - with both internal and external linkage, the behavior is - undefined. + The order of the names, parms, and blocks lists matters, and they + are frequently appended to. To avoid having to walk all the way to + the end of the list on each insertion, or reverse the lists later, + we maintain a pointer to the last list entry for each of the lists. - All declarations that refer to the same object or function shall - have compatible type; otherwise, the behavior is undefined. + The order of the tags, shadowed, and shadowed_tags + lists does not matter, so we just prepend to these lists. */ - Initially only the built-in declarations, which describe compiler - intrinsic functions plus a subset of the standard library, are in - this scope. - - The order of the blocks list matters, and it is frequently appended - to. To avoid having to walk all the way to the end of the list on - each insertion, or reverse the list later, we maintain a pointer to - the last list entry. (FIXME: It should be feasible to use a reversed - list here.) - - The bindings list is strictly in reverse order of declarations; - pop_scope relies on this. */ - - -struct c_scope GTY((chain_next ("%h.outer"))) +struct c_scope GTY(()) { /* The scope containing this one. */ struct c_scope *outer; @@ -315,26 +201,39 @@ struct c_scope GTY((chain_next ("%h.outer"))) /* The next outermost function scope. */ struct c_scope *outer_function; - /* All bindings in this scope. */ - struct c_binding *bindings; + /* All variables, constants, functions, labels, and typedef names. */ + tree names; + tree names_last; + + /* All parameter declarations. Used only in the outermost scope of + a function. */ + tree parms; + tree parms_last; + + /* All structure, union, and enum type tags. */ + tree tags; + + /* For each scope, a list of shadowed outer-scope definitions + to be restored when this scope is popped. + Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and + whose TREE_VALUE is its old definition (a kind of ..._DECL node). */ + tree shadowed; + + /* For each scope, a list of shadowed outer-scope tag definitions + to be restored when this scope is popped. + Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and + whose TREE_VALUE is its old definition (a kind of ..._TYPE node). */ + tree shadowed_tags; /* For each scope (except the global one), a chain of BLOCK nodes for all the scopes that were entered and exited one level down. */ tree blocks; tree blocks_last; - /* The depth of this scope. Used to keep the ->shadowed chain of - bindings sorted innermost to outermost. */ - unsigned int depth : 28; - /* True if we are currently filling this scope with parameter declarations. */ BOOL_BITFIELD parm_flag : 1; - /* True if we saw [*] in this scope. Used to give an error messages - if these appears in a function definition. */ - BOOL_BITFIELD had_vla_unspec : 1; - /* True if we already complained about forward parameter decls in this scope. This prevents double warnings on foo (int a; int b; ...) */ @@ -354,28 +253,20 @@ struct c_scope GTY((chain_next ("%h.outer"))) static GTY(()) struct c_scope *current_scope; +/* A chain of c_scope structures awaiting reuse. */ + +static GTY((deletable (""))) struct c_scope *scope_freelist; + /* The innermost function scope. Ordinary (not explicitly declared) labels, bindings to error_mark_node, and the lazily-created bindings of __func__ and its friends get this scope. */ static GTY(()) struct c_scope *current_function_scope; -/* The C file scope. This is reset for each input translation unit. */ - -static GTY(()) struct c_scope *file_scope; - -/* The outermost scope. This is used for all declarations with - external linkage, and only these, hence the name. */ +/* The outermost scope, corresponding to the C "file scope". This is + created when the compiler is started and exists through the entire run. */ -static GTY(()) struct c_scope *external_scope; - -/* A chain of c_scope structures awaiting reuse. */ - -static GTY((deletable)) struct c_scope *scope_freelist; - -/* A chain of c_binding structures awaiting reuse. */ - -static GTY((deletable)) struct c_binding *binding_freelist; +static GTY(()) struct c_scope *global_scope; /* Append VAR to LIST in scope SCOPE. */ #define SCOPE_LIST_APPEND(scope, list, decl) do { \ @@ -403,7 +294,7 @@ static GTY((deletable)) struct c_binding *binding_freelist; static bool keep_next_level_flag; -/* True means the next call to push_scope will be the outermost scope +/* True means the next call to pushlevel will be the outermost scope of a function body, so do not push a new scope, merely cease expecting parameter decls. */ @@ -411,42 +302,32 @@ static bool next_is_function_body; /* Functions called automatically at the beginning and end of execution. */ -static GTY(()) tree static_ctors; -static GTY(()) tree static_dtors; +tree static_ctors, static_dtors; /* Forward declarations. */ -static tree lookup_name_in_scope (tree, struct c_scope *); -static tree c_make_fname_decl (tree, int); -static tree grokdeclarator (const struct c_declarator *, - struct c_declspecs *, - enum decl_context, bool, tree *); -static tree grokparms (struct c_arg_info *, bool); -static void layout_array_type (tree); - -/* T is a statement. Add it to the statement-tree. This is the - C/ObjC version--C++ has a slightly different version of this - function. */ - -tree -add_stmt (tree t) -{ - enum tree_code code = TREE_CODE (t); - if (EXPR_P (t) && code != LABEL_EXPR) - { - if (!EXPR_HAS_LOCATION (t)) - SET_EXPR_LOCATION (t, input_location); - } - - if (code == LABEL_EXPR || code == CASE_LABEL_EXPR) - STATEMENT_LIST_HAS_LABEL (cur_stmt_list) = 1; - - /* Add T to the statement-tree. Non-side-effect statements need to be - recorded during statement expressions. */ - append_to_statement_list_force (t, &cur_stmt_list); - - return t; -} +static struct c_scope *make_scope (void); +static void pop_scope (void); +static tree make_label (tree, location_t); +static void bind_label (tree, tree, struct c_scope *); +static void implicit_decl_warning (tree); +static tree lookup_tag (enum tree_code, tree, int); +static tree lookup_name_current_level (tree); +static tree grokdeclarator (tree, tree, enum decl_context, int, tree *); +static tree grokparms (tree, int); +static void layout_array_type (tree); +static void store_parm_decls_newstyle (void); +static void store_parm_decls_oldstyle (void); +static tree c_make_fname_decl (tree, int); +static void c_expand_body_1 (tree, int); +static tree any_external_decl (tree); +static void record_external_decl (tree); +static void warn_if_shadowing (tree, tree); +static void check_bitfield_type_and_width (tree *, tree *, const char *); +static void clone_underlying_type (tree); +static bool flexible_array_type_p (tree); +static hashval_t link_hash_hash (const void *); +static int link_hash_eq (const void *, const void *); /* States indicating how grokdeclarator() should handle declspecs marked with __attribute__((deprecated)). An object declared as @@ -463,93 +344,17 @@ static enum deprecated_states deprecated_state = DEPRECATED_NORMAL; void c_print_identifier (FILE *file, tree node, int indent) { - print_node (file, "symbol", I_SYMBOL_DECL (node), indent + 4); - print_node (file, "tag", I_TAG_DECL (node), indent + 4); - print_node (file, "label", I_LABEL_DECL (node), indent + 4); + print_node (file, "symbol", IDENTIFIER_SYMBOL_VALUE (node), indent + 4); + print_node (file, "tag", IDENTIFIER_TAG_VALUE (node), indent + 4); + print_node (file, "label", IDENTIFIER_LABEL_VALUE (node), indent + 4); if (C_IS_RESERVED_WORD (node)) { tree rid = ridpointers[C_RID_CODE (node)]; indent_to (file, indent + 4); - fprintf (file, "rid %p \"%s\"", + fprintf (file, "rid " HOST_PTR_PRINTF " \"%s\"", (void *) rid, IDENTIFIER_POINTER (rid)); } } - -/* Establish a binding between NAME, an IDENTIFIER_NODE, and DECL, - which may be any of several kinds of DECL or TYPE or error_mark_node, - in the scope SCOPE. */ -static void -bind (tree name, tree decl, struct c_scope *scope, bool invisible, bool nested) -{ - struct c_binding *b, **here; - - if (binding_freelist) - { - b = binding_freelist; - binding_freelist = b->prev; - } - else - b = GGC_NEW (struct c_binding); - - b->shadowed = 0; - b->decl = decl; - b->id = name; - b->depth = scope->depth; - b->invisible = invisible; - b->nested = nested; - b->inner_comp = 0; - - b->type = 0; - - b->prev = scope->bindings; - scope->bindings = b; - - if (!name) - return; - - switch (TREE_CODE (decl)) - { - case LABEL_DECL: here = &I_LABEL_BINDING (name); break; - case ENUMERAL_TYPE: - case UNION_TYPE: - case RECORD_TYPE: here = &I_TAG_BINDING (name); break; - case VAR_DECL: - case FUNCTION_DECL: - case TYPE_DECL: - case CONST_DECL: - case PARM_DECL: - case ERROR_MARK: here = &I_SYMBOL_BINDING (name); break; - - default: - gcc_unreachable (); - } - - /* Locate the appropriate place in the chain of shadowed decls - to insert this binding. Normally, scope == current_scope and - this does nothing. */ - while (*here && (*here)->depth > scope->depth) - here = &(*here)->shadowed; - - b->shadowed = *here; - *here = b; -} - -/* Clear the binding structure B, stick it on the binding_freelist, - and return the former value of b->prev. This is used by pop_scope - and get_parm_info to iterate destructively over all the bindings - from a given scope. */ -static struct c_binding * -free_binding_and_advance (struct c_binding *b) -{ - struct c_binding *prev = b->prev; - - memset (b, 0, sizeof (struct c_binding)); - b->prev = binding_freelist; - binding_freelist = b; - - return prev; -} - /* Hook called at end of compilation to assume 1 elt for a file-scope tentative array defn that wasn't complete before. */ @@ -562,22 +367,56 @@ c_finish_incomplete_decl (tree decl) tree type = TREE_TYPE (decl); if (type != error_mark_node && TREE_CODE (type) == ARRAY_TYPE - && !DECL_EXTERNAL (decl) + && ! DECL_EXTERNAL (decl) && TYPE_DOMAIN (type) == 0) { - warning (0, "array %q+D assumed to have one element", decl); + warning ("%Jarray '%D' assumed to have one element", decl, decl); - complete_array_type (&TREE_TYPE (decl), NULL_TREE, true); + complete_array_type (type, NULL_TREE, 1); layout_decl (decl, 0); } } } +/* Reuse or create a struct for this scope. */ + +static struct c_scope * +make_scope (void) +{ + struct c_scope *result; + if (scope_freelist) + { + result = scope_freelist; + scope_freelist = result->outer; + } + else + result = ggc_alloc_cleared (sizeof (struct c_scope)); + + return result; +} + +/* Remove the topmost scope from the stack and add it to the + free list, updating current_function_scope if necessary. */ + +static void +pop_scope (void) +{ + struct c_scope *scope = current_scope; + + current_scope = scope->outer; + if (scope->function_body) + current_function_scope = scope->outer_function; + + memset (scope, 0, sizeof (struct c_scope)); + scope->outer = scope_freelist; + scope_freelist = scope; +} + /* The Objective-C front-end often needs to determine the current scope. */ void * -objc_get_current_scope (void) +get_current_scope (void) { return current_scope; } @@ -589,27 +428,30 @@ void objc_mark_locals_volatile (void *enclosing_blk) { struct c_scope *scope; - struct c_binding *b; for (scope = current_scope; scope && scope != enclosing_blk; scope = scope->outer) { - for (b = scope->bindings; b; b = b->prev) - objc_volatilize_decl (b->decl); + tree decl; + for (decl = scope->names; decl; decl = TREE_CHAIN (decl)) + { + DECL_REGISTER (decl) = 0; + TREE_THIS_VOLATILE (decl) = 1; + } /* Do not climb up past the current function. */ if (scope->function_body) break; } } -/* Nonzero if we are currently in file scope. */ +/* Nonzero if we are currently in the global scope. */ int global_bindings_p (void) { - return current_scope == file_scope && !c_override_global_bindings_to_false; + return current_scope == global_scope; } void @@ -626,8 +468,19 @@ declare_parm_level (void) current_scope->parm_flag = true; } +/* Nonzero if currently making parm declarations. */ + +int +in_parm_level_p (void) +{ + return current_scope->parm_flag; +} + +/* Enter a new scope. The dummy parameter is for signature + compatibility with lang_hooks.decls.pushlevel. */ + void -push_scope (void) +pushlevel (int dummy ATTRIBUTE_UNUSED) { if (next_is_function_body) { @@ -652,58 +505,49 @@ push_scope (void) } else { - struct c_scope *scope; - if (scope_freelist) - { - scope = scope_freelist; - scope_freelist = scope->outer; - } - else - scope = GGC_CNEW (struct c_scope); + struct c_scope *scope = make_scope (); scope->keep = keep_next_level_flag; scope->outer = current_scope; - scope->depth = current_scope ? (current_scope->depth + 1) : 0; - - /* Check for scope depth overflow. Unlikely (2^28 == 268,435,456) but - possible. */ - if (current_scope && scope->depth == 0) - { - scope->depth--; - sorry ("GCC supports only %u nested scopes", scope->depth); - } - current_scope = scope; keep_next_level_flag = false; } } -/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT. */ +/* Exit a scope. Restore the state of the identifier-decl mappings + that were in effect when this scope was entered. -static void -set_type_context (tree type, tree context) -{ - for (type = TYPE_MAIN_VARIANT (type); type; - type = TYPE_NEXT_VARIANT (type)) - TYPE_CONTEXT (type) = context; -} + If KEEP is KEEP_YES (1), this scope had explicit declarations, so + create a BLOCK node to record its declarations and subblocks for + debugging output. If KEEP is KEEP_MAYBE, do so only if the names + or tags lists are nonempty. -/* Exit a scope. Restore the state of the identifier-decl mappings - that were in effect when this scope was entered. Return a BLOCK - node containing all the DECLs in this scope that are of interest - to debug info generation. */ + The second parameter is ignored; it is present only for + signature compatibility with lang_hooks.decls.poplevel. + + If FUNCTIONBODY is nonzero, this level is the body of a function, + even if current_scope->function_body is not set. This is used + by language-independent code that generates synthetic functions, + and cannot set current_scope->function_body. + + FIXME: Eliminate the need for all arguments. */ tree -pop_scope (void) +poplevel (int keep, int dummy ATTRIBUTE_UNUSED, int functionbody) { struct c_scope *scope = current_scope; - tree block, context, p; - struct c_binding *b; + tree block; + tree decl; + tree p; + + /* The following line does not use |= due to a bug in HP's C compiler. */ + scope->function_body = scope->function_body | functionbody; - bool functionbody = scope->function_body; - bool keep = functionbody || scope->keep || scope->bindings; + if (keep == KEEP_MAYBE) + keep = (scope->names || scope->tags); - c_end_vm_scope (scope->depth); + keep |= scope->keep; + keep |= scope->function_body; /* If appropriate, create a BLOCK to record the decls for the life of this function. */ @@ -711,170 +555,128 @@ pop_scope (void) if (keep) { block = make_node (BLOCK); + BLOCK_VARS (block) = scope->names; BLOCK_SUBBLOCKS (block) = scope->blocks; TREE_USED (block) = 1; + } - /* In each subblock, record that this is its superior. */ - for (p = scope->blocks; p; p = TREE_CHAIN (p)) - BLOCK_SUPERCONTEXT (p) = block; + /* In each subblock, record that this is its superior. */ + for (p = scope->blocks; p; p = TREE_CHAIN (p)) + BLOCK_SUPERCONTEXT (p) = block; - BLOCK_VARS (block) = 0; - } + /* Clear out the variable bindings in this scope. - /* The TYPE_CONTEXTs for all of the tagged types belonging to this - scope must be set so that they point to the appropriate - construct, i.e. either to the current FUNCTION_DECL node, or - else to the BLOCK node we just constructed. + Propagate TREE_ADDRESSABLE from nested functions to their + containing functions. - Note that for tagged types whose scope is just the formal - parameter list for some function type specification, we can't - properly set their TYPE_CONTEXTs here, because we don't have a - pointer to the appropriate FUNCTION_TYPE node readily available - to us. For those cases, the TYPE_CONTEXTs of the relevant tagged - type nodes get set in `grokdeclarator' as soon as we have created - the FUNCTION_TYPE node which will represent the "scope" for these - "parameter list local" tagged types. */ - if (scope->function_body) - context = current_function_decl; - else if (scope == file_scope) - { - tree file_decl = build_decl (TRANSLATION_UNIT_DECL, 0, 0); - TREE_CHAIN (file_decl) = all_translation_units; - all_translation_units = file_decl; - context = file_decl; - } - else - context = block; + Issue warnings for unused variables and labels, and errors for + undefined labels, if there are any. */ - /* Clear all bindings in this scope. */ - for (b = scope->bindings; b; b = free_binding_and_advance (b)) + for (p = scope->names; p; p = TREE_CHAIN (p)) { - p = b->decl; switch (TREE_CODE (p)) { case LABEL_DECL: - /* Warnings for unused labels, errors for undefined labels. */ if (TREE_USED (p) && !DECL_INITIAL (p)) { - error ("label %q+D used but not defined", p); + error ("%Jlabel `%D' used but not defined", p, p); DECL_INITIAL (p) = error_mark_node; } else if (!TREE_USED (p) && warn_unused_label) { if (DECL_INITIAL (p)) - warning (0, "label %q+D defined but not used", p); + warning ("%Jlabel `%D' defined but not used", p, p); else - warning (0, "label %q+D declared but not defined", p); + warning ("%Jlabel `%D' declared but not defined", p, p); } - /* Labels go in BLOCK_VARS. */ - TREE_CHAIN (p) = BLOCK_VARS (block); - BLOCK_VARS (block) = p; - gcc_assert (I_LABEL_BINDING (b->id) == b); - I_LABEL_BINDING (b->id) = b->shadowed; - break; - - case ENUMERAL_TYPE: - case UNION_TYPE: - case RECORD_TYPE: - set_type_context (p, context); - /* Types may not have tag-names, in which case the type - appears in the bindings list with b->id NULL. */ - if (b->id) - { - gcc_assert (I_TAG_BINDING (b->id) == b); - I_TAG_BINDING (b->id) = b->shadowed; - } + IDENTIFIER_LABEL_VALUE (DECL_NAME (p)) = 0; break; case FUNCTION_DECL: - /* Propagate TREE_ADDRESSABLE from nested functions to their - containing functions. */ - if (!TREE_ASM_WRITTEN (p) + if (! TREE_ASM_WRITTEN (p) && DECL_INITIAL (p) != 0 && TREE_ADDRESSABLE (p) && DECL_ABSTRACT_ORIGIN (p) != 0 && DECL_ABSTRACT_ORIGIN (p) != p) TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (p)) = 1; - if (!DECL_EXTERNAL (p) - && DECL_INITIAL (p) == 0) - { - error ("nested function %q+D declared but never defined", p); - undef_nested_function = true; - } - goto common_symbol; + goto normal; case VAR_DECL: - /* Warnings for unused variables. */ - if (!TREE_USED (p) - && !TREE_NO_WARNING (p) + /* Keep this in sync with stmt.c:warn_about_unused_variables. + No warnings when the global scope is popped because the + global scope isn't popped for the last translation unit, + so the warnings are done in c_write_global_declaration. */ + if (warn_unused_variable && scope != global_scope + && !TREE_USED (p) && !DECL_IN_SYSTEM_HEADER (p) && DECL_NAME (p) - && !DECL_ARTIFICIAL (p) - && scope != file_scope - && scope != external_scope) - warning (OPT_Wunused_variable, "unused variable %q+D", p); - - if (b->inner_comp) - { - error ("type of array %q+D completed incompatibly with" - " implicit initialization", p); - } - - /* Fall through. */ - case TYPE_DECL: - case CONST_DECL: - common_symbol: - /* All of these go in BLOCK_VARS, but only if this is the - binding in the home scope. */ - if (!b->nested) - { - TREE_CHAIN (p) = BLOCK_VARS (block); - BLOCK_VARS (block) = p; - } - /* If this is the file scope, and we are processing more - than one translation unit in this compilation, set - DECL_CONTEXT of each decl to the TRANSLATION_UNIT_DECL. - This makes same_translation_unit_p work, and causes - static declarations to be given disambiguating suffixes. */ - if (scope == file_scope && num_in_fnames > 1) - { - DECL_CONTEXT (p) = context; - if (TREE_CODE (p) == TYPE_DECL) - set_type_context (TREE_TYPE (p), context); - } + && !DECL_ARTIFICIAL (p)) + warning ("%Junused variable `%D'", p, p); + /* fall through */ - /* Fall through. */ - /* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have - already been put there by store_parm_decls. Unused- - parameter warnings are handled by function.c. - error_mark_node obviously does not go in BLOCK_VARS and - does not get unused-variable warnings. */ - case PARM_DECL: - case ERROR_MARK: - /* It is possible for a decl not to have a name. We get - here with b->id NULL in this case. */ - if (b->id) + default: + normal: + if (DECL_NAME (p)) { - gcc_assert (I_SYMBOL_BINDING (b->id) == b); - I_SYMBOL_BINDING (b->id) = b->shadowed; - if (b->shadowed && b->shadowed->type) - TREE_TYPE (b->shadowed->decl) = b->shadowed->type; + if (DECL_EXTERNAL (p) && scope != global_scope) + /* External decls stay in the symbol-value slot but are + inaccessible. */ + C_DECL_INVISIBLE (p) = 1; + else + IDENTIFIER_SYMBOL_VALUE (DECL_NAME (p)) = 0; } break; - - default: - gcc_unreachable (); } } + /* Clear out the parameter bindings in this scope, if any. + Unused-parameter warnings are handled by function.c. */ + for (p = scope->parms; p; p = TREE_CHAIN (p)) + if (DECL_NAME (p)) + IDENTIFIER_SYMBOL_VALUE (DECL_NAME (p)) = 0; - /* Dispose of the block that we just made inside some higher level. */ - if ((scope->function_body || scope == file_scope) && context) + /* Clear out the tag-meanings declared in this scope. + + Set the TYPE_CONTEXTs for all of the tagged types belonging to + this scope so that they point to the appropriate construct, i.e. + either to the current FUNCTION_DECL node, or else to the BLOCK + node we just constructed. + + Note that for tagged types whose scope is just the formal + parameter list for some function type specification, we can't + properly set their TYPE_CONTEXTs here, because we don't have a + pointer to the appropriate FUNCTION_TYPE node readily available + to us. For those cases, the TYPE_CONTEXTs of the relevant tagged + type nodes get set in `grokdeclarator' as soon as we have created + the FUNCTION_TYPE node which will represent the "scope" for these + "parameter list local" tagged types. */ + + decl = scope->function_body ? current_function_decl : block; + for (p = scope->tags; p; p = TREE_CHAIN (p)) { - DECL_INITIAL (context) = block; - BLOCK_SUPERCONTEXT (block) = context; + if (TREE_PURPOSE (p)) + IDENTIFIER_TAG_VALUE (TREE_PURPOSE (p)) = 0; + if (decl) + TYPE_CONTEXT (TREE_VALUE (p)) = decl; } + + /* Restore all name- and label-meanings from outer scopes that were + shadowed by this scope. */ + for (p = scope->shadowed; p; p = TREE_CHAIN (p)) + if (TREE_VALUE (p) && TREE_CODE (TREE_VALUE (p)) == LABEL_DECL) + IDENTIFIER_LABEL_VALUE (TREE_PURPOSE (p)) = TREE_VALUE (p); + else + IDENTIFIER_SYMBOL_VALUE (TREE_PURPOSE (p)) = TREE_VALUE (p); + + /* Restore all tag-meanings from outer scopes that were shadowed by + this scope. */ + for (p = scope->shadowed_tags; p; p = TREE_CHAIN (p)) + IDENTIFIER_TAG_VALUE (TREE_PURPOSE (p)) = TREE_VALUE (p); + + /* Dispose of the block that we just made inside some higher level. */ + if (scope->function_body && current_function_decl) + DECL_INITIAL (current_function_decl) = block; else if (scope->outer) { if (block) @@ -887,62 +689,9 @@ pop_scope (void) } /* Pop the current scope, and free the structure for reuse. */ - current_scope = scope->outer; - if (scope->function_body) - current_function_scope = scope->outer_function; - - memset (scope, 0, sizeof (struct c_scope)); - scope->outer = scope_freelist; - scope_freelist = scope; - - return block; -} - -void -push_file_scope (void) -{ - tree decl; - - if (file_scope) - return; - - push_scope (); - file_scope = current_scope; - - start_fname_decls (); - - for (decl = visible_builtins; decl; decl = TREE_CHAIN (decl)) - bind (DECL_NAME (decl), decl, file_scope, - /*invisible=*/false, /*nested=*/true); -} - -void -pop_file_scope (void) -{ - /* In case there were missing closebraces, get us back to the global - binding level. */ - while (current_scope != file_scope) - pop_scope (); - - /* __FUNCTION__ is defined at file scope (""). This - call may not be necessary as my tests indicate it - still works without it. */ - finish_fname_decls (); - - /* This is the point to write out a PCH if we're doing that. - In that case we do not want to do anything else. */ - if (pch_file) - { - c_common_write_pch (); - return; - } - - /* Pop off the file scope and close this translation unit. */ pop_scope (); - file_scope = 0; - maybe_apply_pending_pragma_weaks (); - cgraph_finalize_compilation_unit (); + return block; } /* Insert BLOCK at the end of the list of subblocks of the current @@ -955,6 +704,15 @@ insert_block (tree block) TREE_USED (block) = 1; SCOPE_LIST_APPEND (current_scope, blocks, block); } + +/* Set the BLOCK node for the innermost scope (the one we are + currently in). The RTL expansion machinery requires us to provide + this hook, but it is not useful in function-at-a-time mode. */ + +void +set_block (tree block ATTRIBUTE_UNUSED) +{ +} /* Push a definition or a declaration of struct, union or enum tag "name". "type" should be the type node. @@ -963,13 +721,24 @@ insert_block (tree block) Note that the definition may really be just a forward reference. In that case, the TYPE_SIZE will be zero. */ -static void +void pushtag (tree name, tree type) { + struct c_scope *b = current_scope; + /* Record the identifier as the type's name if it has none. */ - if (name && !TYPE_NAME (type)) - TYPE_NAME (type) = name; - bind (name, type, current_scope, /*invisible=*/false, /*nested=*/false); + if (name) + { + if (TYPE_NAME (type) == 0) + TYPE_NAME (type) = name; + + if (IDENTIFIER_TAG_VALUE (name)) + b->shadowed_tags = tree_cons (name, IDENTIFIER_TAG_VALUE (name), + b->shadowed_tags); + IDENTIFIER_TAG_VALUE (name) = type; + } + + b->tags = tree_cons (name, type, b->tags); /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE will be the tagged type we just added to the current scope. This fake @@ -981,7 +750,7 @@ pushtag (tree name, tree type) TYPE_STUB_DECL (type) = pushdecl (build_decl (TYPE_DECL, NULL_TREE, type)); /* An approximation for now, so we can tell this is a function-scope tag. - This will be updated in pop_scope. */ + This will be updated in poplevel. */ TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type)); } @@ -1009,10 +778,10 @@ match_builtin_function_types (tree newtype, tree oldtype) while (oldargs || newargs) { - if (!oldargs - || !newargs - || !TREE_VALUE (oldargs) - || !TREE_VALUE (newargs) + if (! oldargs + || ! newargs + || ! TREE_VALUE (oldargs) + || ! TREE_VALUE (newargs) || TYPE_MODE (TREE_VALUE (oldargs)) != TYPE_MODE (TREE_VALUE (newargs))) return 0; @@ -1025,9 +794,9 @@ match_builtin_function_types (tree newtype, tree oldtype) return build_type_attribute_variant (trytype, TYPE_ATTRIBUTES (oldtype)); } -/* Subroutine of diagnose_mismatched_decls. Check for function type +/* Subroutine of diagnose_mismathed_decls. Check for function type mismatch involving an empty arglist vs a nonempty one and give clearer - diagnostics. */ + diagnostics. */ static void diagnose_arglist_conflict (tree newdecl, tree olddecl, tree newtype, tree oldtype) @@ -1035,7 +804,7 @@ diagnose_arglist_conflict (tree newdecl, tree olddecl, tree t; if (TREE_CODE (olddecl) != FUNCTION_DECL - || !comptypes (TREE_TYPE (oldtype), TREE_TYPE (newtype)) + || !comptypes (TREE_TYPE (oldtype), TREE_TYPE (newtype), COMPARE_STRICT) || !((TYPE_ARG_TYPES (oldtype) == 0 && DECL_INITIAL (olddecl) == 0) || (TYPE_ARG_TYPES (newtype) == 0 && DECL_INITIAL (newdecl) == 0))) @@ -1051,14 +820,14 @@ diagnose_arglist_conflict (tree newdecl, tree olddecl, if (TREE_CHAIN (t) == 0 && TYPE_MAIN_VARIANT (type) != void_type_node) { - inform ("a parameter list with an ellipsis can%'t match " + inform ("a parameter list with an ellipsis can't match " "an empty parameter name list declaration"); break; } if (c_type_promotes_to (type) != type) { - inform ("an argument type that has a default promotion can%'t match " + inform ("an argument type that has a default promotion can't match " "an empty parameter name list declaration"); break; } @@ -1075,7 +844,8 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype) tree newargs, oldargs; int i; -#define END_OF_ARGLIST(t) ((t) == void_type_node) + /* ??? Elsewhere TYPE_MAIN_VARIANT is not used in this context. */ +#define END_OF_ARGLIST(t) (TYPE_MAIN_VARIANT (t) == void_type_node) oldargs = TYPE_ACTUAL_ARG_TYPES (oldtype); newargs = TYPE_ARG_TYPES (newtype); @@ -1086,12 +856,6 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype) tree oldargtype = TREE_VALUE (oldargs); tree newargtype = TREE_VALUE (newargs); - if (oldargtype == error_mark_node || newargtype == error_mark_node) - return false; - - oldargtype = TYPE_MAIN_VARIANT (oldargtype); - newargtype = TYPE_MAIN_VARIANT (newargtype); - if (END_OF_ARGLIST (oldargtype) && END_OF_ARGLIST (newargtype)) break; @@ -1099,24 +863,23 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype) agree on the number of arguments. */ if (END_OF_ARGLIST (oldargtype)) { - error ("prototype for %q+D declares more arguments " - "than previous old-style definition", newdecl); + error ("%Jprototype for '%D' declares more arguments " + "than previous old-style definition", newdecl, newdecl); return false; } else if (END_OF_ARGLIST (newargtype)) { - error ("prototype for %q+D declares fewer arguments " - "than previous old-style definition", newdecl); + error ("%Jprototype for '%D' declares fewer arguments " + "than previous old-style definition", newdecl, newdecl); return false; } /* Type for passing arg must be consistent with that declared for the arg. */ - else if (!comptypes (oldargtype, newargtype)) + else if (! comptypes (oldargtype, newargtype, COMPARE_STRICT)) { - error ("prototype for %q+D declares argument %d" - " with incompatible type", - newdecl, i); + error ("%Jprototype for '%D' declares arg %d with incompatible type", + newdecl, newdecl, i); return false; } @@ -1127,8 +890,8 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype) /* If we get here, no errors were found, but do issue a warning for this poor-style construct. */ - warning (0, "prototype for %q+D follows non-prototype definition", - newdecl); + warning ("%Jprototype for '%D' follows non-prototype definition", + newdecl, newdecl); return true; #undef END_OF_ARGLIST } @@ -1137,16 +900,16 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype) first in a pair of mismatched declarations, using the diagnostic function DIAG. */ static void -locate_old_decl (tree decl, void (*diag)(const char *, ...) ATTRIBUTE_GCC_CDIAG(1,2)) +locate_old_decl (tree decl, void (*diag)(const char *, ...)) { if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)) ; else if (DECL_INITIAL (decl)) - diag (G_("previous definition of %q+D was here"), decl); + diag (N_("%Jprevious definition of '%D' was here"), decl, decl); else if (C_DECL_IMPLICIT (decl)) - diag (G_("previous implicit declaration of %q+D was here"), decl); + diag (N_("%Jprevious implicit declaration of '%D' was here"), decl, decl); else - diag (G_("previous declaration of %q+D was here"), decl); + diag (N_("%Jprevious declaration of '%D' was here"), decl, decl); } /* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL. @@ -1164,10 +927,6 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, tree newtype, oldtype; bool pedwarned = false; bool warned = false; - bool retval = true; - -#define DECL_EXTERN_INLINE(DECL) (DECL_DECLARED_INLINE_P (DECL) \ - && DECL_EXTERNAL (DECL)) /* If we have error_mark_node for either decl or type, just discard the previous decl - we're in an error cascade already. */ @@ -1182,19 +941,19 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, unless OLDDECL is a builtin. OLDDECL will be discarded in any case. */ if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) { - if (!(TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_BUILT_IN (olddecl) - && !C_DECL_DECLARED_BUILTIN (olddecl))) + if (TREE_CODE (olddecl) != FUNCTION_DECL + || !DECL_BUILT_IN (olddecl) || !C_DECL_INVISIBLE (olddecl)) { - error ("%q+D redeclared as different kind of symbol", newdecl); + error ("%J'%D' redeclared as different kind of symbol", + newdecl, newdecl); locate_old_decl (olddecl, error); } else if (TREE_PUBLIC (newdecl)) - warning (0, "built-in function %q+D declared as non-function", - newdecl); - else - warning (OPT_Wshadow, "declaration of %q+D shadows " - "a built-in function", newdecl); + warning ("%Jbuilt-in function '%D' declared as non-function", + newdecl, newdecl); + else if (warn_shadow) + warning ("%Jshadowing built-in function '%D'", + newdecl, newdecl); return false; } @@ -1202,34 +961,34 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, given scope. */ if (TREE_CODE (olddecl) == CONST_DECL) { - error ("redeclaration of enumerator %q+D", newdecl); + error ("%Jredeclaration of enumerator `%D'", newdecl, newdecl); locate_old_decl (olddecl, error); return false; } - if (!comptypes (oldtype, newtype)) + if (!comptypes (oldtype, newtype, COMPARE_STRICT)) { if (TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_BUILT_IN (olddecl) && !C_DECL_DECLARED_BUILTIN (olddecl)) + && DECL_BUILT_IN (olddecl) && C_DECL_INVISIBLE (olddecl)) { /* Accept harmless mismatch in function types. This is for the ffs and fprintf builtins. */ tree trytype = match_builtin_function_types (newtype, oldtype); - if (trytype && comptypes (newtype, trytype)) + if (trytype && comptypes (newtype, trytype, COMPARE_STRICT)) *oldtypep = oldtype = trytype; else { /* If types don't match for a built-in, throw away the built-in. No point in calling locate_old_decl here, it - won't print anything. */ - warning (0, "conflicting types for built-in function %q+D", - newdecl); + won't print anything. */ + warning ("%Jconflicting types for built-in function '%D'", + newdecl, newdecl); return false; } } else if (TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_IS_BUILTIN (olddecl)) + && DECL_SOURCE_LINE (olddecl) == 0) { /* A conflicting function declaration for a predeclared function that isn't actually built in. Objective C uses @@ -1245,32 +1004,17 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, else if (TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node - && C_FUNCTION_IMPLICIT_INT (newdecl) && !DECL_INITIAL (olddecl)) + && C_FUNCTION_IMPLICIT_INT (newdecl)) { - pedwarn ("conflicting types for %q+D", newdecl); + pedwarn ("%Jconflicting types for '%D'", newdecl, newdecl); /* Make sure we keep void as the return type. */ TREE_TYPE (newdecl) = *newtypep = newtype = oldtype; C_FUNCTION_IMPLICIT_INT (newdecl) = 0; pedwarned = true; } - /* Permit void foo (...) to match an earlier call to foo (...) with - no declared type (thus, implicitly int). */ - else if (TREE_CODE (newdecl) == FUNCTION_DECL - && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == void_type_node - && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == integer_type_node - && C_DECL_IMPLICIT (olddecl) && !DECL_INITIAL (olddecl)) - { - pedwarn ("conflicting types for %q+D", newdecl); - /* Make sure we keep void as the return type. */ - TREE_TYPE (olddecl) = *oldtypep = oldtype = newtype; - pedwarned = true; - } else { - if (TYPE_QUALS (newtype) != TYPE_QUALS (oldtype)) - error ("conflicting type qualifiers for %q+D", newdecl); - else - error ("conflicting types for %q+D", newdecl); + error ("%Jconflicting types for '%D'", newdecl, newdecl); diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype); locate_old_decl (olddecl, error); return false; @@ -1283,9 +1027,9 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, if (TREE_CODE (newdecl) == TYPE_DECL) { if (DECL_IN_SYSTEM_HEADER (newdecl) || DECL_IN_SYSTEM_HEADER (olddecl)) - return true; /* Allow OLDDECL to continue in use. */ - - error ("redefinition of typedef %q+D", newdecl); + return true; /* allow OLDDECL to continue in use */ + + error ("%Jredefinition of typedef '%D'", newdecl, newdecl); locate_old_decl (olddecl, error); return false; } @@ -1296,7 +1040,6 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, Multiple definitions are not allowed (6.9p3,5) but GCC permits two definitions if one is 'extern inline' and one is not. The non- extern-inline definition supersedes the extern-inline definition. */ - else if (TREE_CODE (newdecl) == FUNCTION_DECL) { /* If you declare a built-in function name as static, or @@ -1304,39 +1047,28 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, can't validate the argument list) the built-in definition is overridden, but optionally warn this was a bad choice of name. */ if (DECL_BUILT_IN (olddecl) - && !C_DECL_DECLARED_BUILTIN (olddecl) + && C_DECL_INVISIBLE (olddecl) && (!TREE_PUBLIC (newdecl) || (DECL_INITIAL (newdecl) && !TYPE_ARG_TYPES (TREE_TYPE (newdecl))))) { - warning (OPT_Wshadow, "declaration of %q+D shadows " - "a built-in function", newdecl); + if (warn_shadow) + warning ("%Jshadowing built-in function '%D'", newdecl, newdecl); /* Discard the old built-in function. */ return false; } - + if (DECL_INITIAL (newdecl)) { - if (DECL_INITIAL (olddecl)) + if (DECL_INITIAL (olddecl) + && !(DECL_DECLARED_INLINE_P (olddecl) + && DECL_EXTERNAL (olddecl) + && !(DECL_DECLARED_INLINE_P (newdecl) + && DECL_EXTERNAL (newdecl)))) { - /* If both decls are in the same TU and the new declaration - isn't overriding an extern inline reject the new decl. - When we handle c99 style inline rules we'll want to reject - the following: - - DECL_EXTERN_INLINE (olddecl) - && !DECL_EXTERN_INLINE (newdecl) - - if they're in the same translation unit. Until we implement - the full semantics we accept the construct. */ - if (!(DECL_EXTERN_INLINE (olddecl) - && !DECL_EXTERN_INLINE (newdecl)) - && same_translation_unit_p (newdecl, olddecl)) - { - error ("redefinition of %q+D", newdecl); - locate_old_decl (olddecl, error); - return false; - } + error ("%Jredefinition of '%D'", newdecl, newdecl); + locate_old_decl (olddecl, error); + return false; } } /* If we have a prototype after an old-style function definition, @@ -1349,67 +1081,47 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, locate_old_decl (olddecl, error); return false; } - /* A non-static declaration (even an "extern") followed by a - static declaration is undefined behavior per C99 6.2.2p3-5,7. - The same is true for a static forward declaration at block - scope followed by a non-static declaration/definition at file - scope. Static followed by non-static at the same scope is - not undefined behavior, and is the most convenient way to get - some effects (see e.g. what unwind-dw2-fde-glibc.c does to - the definition of _Unwind_Find_FDE in unwind-dw2-fde.c), but - we do diagnose it if -Wtraditional. */ + /* Mismatched non-static and static is considered poor style. + We only diagnose static then non-static if -Wtraditional, + because it is the most convenient way to get some effects + (see e.g. what unwind-dw2-fde-glibc.c does to the definition + of _Unwind_Find_FDE in unwind-dw2-fde.c). Revisit? */ if (TREE_PUBLIC (olddecl) && !TREE_PUBLIC (newdecl)) { - /* Two exceptions to the rule. If olddecl is an extern - inline, or a predeclared function that isn't actually - built in, newdecl silently overrides olddecl. The latter - occur only in Objective C; see also above. (FIXME: Make - Objective C use normal builtins.) */ - if (!DECL_IS_BUILTIN (olddecl) - && !DECL_EXTERN_INLINE (olddecl)) + /* A static function declaration for a predeclared function + that isn't actually built in, silently overrides the + default. Objective C uses these. See also above. + FIXME: Make Objective C use normal builtins. */ + if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_SOURCE_LINE (olddecl) == 0) + return false; + else { - error ("static declaration of %q+D follows " - "non-static declaration", newdecl); - locate_old_decl (olddecl, error); + warning ("%Jstatic declaration of '%D' follows " + "non-static declaration", newdecl, newdecl); + warned = true; } - return false; } - else if (TREE_PUBLIC (newdecl) && !TREE_PUBLIC (olddecl)) + else if (TREE_PUBLIC (newdecl) && !TREE_PUBLIC (olddecl) + && warn_traditional) { - if (DECL_CONTEXT (olddecl)) - { - error ("non-static declaration of %q+D follows " - "static declaration", newdecl); - locate_old_decl (olddecl, error); - return false; - } - else if (warn_traditional) - { - warning (OPT_Wtraditional, "non-static declaration of %q+D " - "follows static declaration", newdecl); - warned = true; - } + warning ("%Jnon-static declaration of '%D' follows " + "static declaration", newdecl, newdecl); + warned = true; } } else if (TREE_CODE (newdecl) == VAR_DECL) { /* Only variables can be thread-local, and all declarations must agree on this property. */ - if (C_DECL_THREADPRIVATE_P (olddecl) && !DECL_THREAD_LOCAL_P (newdecl)) - { - /* Nothing to check. Since OLDDECL is marked threadprivate - and NEWDECL does not have a thread-local attribute, we - will merge the threadprivate attribute into NEWDECL. */ - ; - } - else if (DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl)) + if (DECL_THREAD_LOCAL (newdecl) != DECL_THREAD_LOCAL (olddecl)) { - if (DECL_THREAD_LOCAL_P (newdecl)) - error ("thread-local declaration of %q+D follows " - "non-thread-local declaration", newdecl); + if (DECL_THREAD_LOCAL (newdecl)) + error ("%Jthread-local declaration of '%D' follows " + "non-thread-local declaration", newdecl, newdecl); else - error ("non-thread-local declaration of %q+D follows " - "thread-local declaration", newdecl); + error ("%Jnon-thread-local declaration of '%D' follows " + "thread-local declaration", newdecl, newdecl); locate_old_decl (olddecl, error); return false; @@ -1418,46 +1130,25 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, /* Multiple initialized definitions are not allowed (6.9p3,5). */ if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl)) { - error ("redefinition of %q+D", newdecl); + error ("%Jredefinition of '%D'", newdecl, newdecl); locate_old_decl (olddecl, error); return false; } - /* Objects declared at file scope: if the first declaration had - external linkage (even if it was an external reference) the - second must have external linkage as well, or the behavior is - undefined. If the first declaration had internal linkage, then - the second must too, or else be an external reference (in which - case the composite declaration still has internal linkage). - As for function declarations, we warn about the static-then- - extern case only for -Wtraditional. See generally 6.2.2p3-5,7. */ - if (DECL_FILE_SCOPE_P (newdecl) - && TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl)) + /* Objects declared at file scope: if at least one is 'extern', + it's fine (6.2.2p4); otherwise the linkage must agree (6.2.2p7). */ + if (DECL_FILE_SCOPE_P (newdecl)) { - if (DECL_EXTERNAL (newdecl)) - { - if (!DECL_FILE_SCOPE_P (olddecl)) - { - error ("extern declaration of %q+D follows " - "declaration with no linkage", newdecl); - locate_old_decl (olddecl, error); - return false; - } - else if (warn_traditional) - { - warning (OPT_Wtraditional, "non-static declaration of %q+D " - "follows static declaration", newdecl); - warned = true; - } - } - else + if (!DECL_EXTERNAL (newdecl) + && !DECL_EXTERNAL (olddecl) + && TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl)) { if (TREE_PUBLIC (newdecl)) - error ("non-static declaration of %q+D follows " - "static declaration", newdecl); + error ("%Jnon-static declaration of '%D' follows " + "static declaration", newdecl, newdecl); else - error ("static declaration of %q+D follows " - "non-static declaration", newdecl); + error ("%Jstatic declaration of '%D' follows " + "non-static declaration", newdecl, newdecl); locate_old_decl (olddecl, error); return false; @@ -1465,37 +1156,32 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, } /* Two objects with the same name declared at the same block scope must both be external references (6.7p3). */ - else if (!DECL_FILE_SCOPE_P (newdecl)) + else if (DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl) + && (!DECL_EXTERNAL (newdecl) || !DECL_EXTERNAL (olddecl))) { if (DECL_EXTERNAL (newdecl)) - { - /* Extern with initializer at block scope, which will - already have received an error. */ - } + error ("%Jextern declaration of '%D' follows " + "declaration with no linkage", newdecl, newdecl); else if (DECL_EXTERNAL (olddecl)) - { - error ("declaration of %q+D with no linkage follows " - "extern declaration", newdecl); - locate_old_decl (olddecl, error); - } + error ("%Jdeclaration of '%D' with no linkage follows " + "extern declaration", newdecl, newdecl); else - { - error ("redeclaration of %q+D with no linkage", newdecl); - locate_old_decl (olddecl, error); - } + error ("%Jredeclaration of '%D' with no linkage", + newdecl, newdecl); + locate_old_decl (olddecl, error); return false; } } /* warnings */ - /* All decls must agree on a visibility. */ - if (CODE_CONTAINS_STRUCT (TREE_CODE (newdecl), TS_DECL_WITH_VIS) - && DECL_VISIBILITY_SPECIFIED (newdecl) && DECL_VISIBILITY_SPECIFIED (olddecl) + /* All decls must agree on a non-default visibility. */ + if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT + && DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) { - warning (0, "redeclaration of %q+D with different visibility " - "(old visibility preserved)", newdecl); + warning ("%Jredeclaration of '%D' with different visibility " + "(old visibility preserved)", newdecl, newdecl); warned = true; } @@ -1505,56 +1191,70 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, if (DECL_DECLARED_INLINE_P (newdecl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) { - warning (OPT_Wattributes, "inline declaration of %qD follows " - "declaration with attribute noinline", newdecl); + warning ("%Jinline declaration of '%D' follows " + "declaration with attribute noinline", newdecl, newdecl); warned = true; } else if (DECL_DECLARED_INLINE_P (olddecl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) { - warning (OPT_Wattributes, "declaration of %q+D with attribute " - "noinline follows inline declaration ", newdecl); + warning ("%Jdeclaration of '%D' with attribute noinline follows " + "inline declaration ", newdecl, newdecl); warned = true; } /* Inline declaration after use or definition. ??? Should we still warn about this now we have unit-at-a-time - mode and can get it right? - Definitely don't complain if the decls are in different translation - units. */ - if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl) - && same_translation_unit_p (olddecl, newdecl)) + mode and can get it right? */ + if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl)) { if (TREE_USED (olddecl)) { - warning (0, "%q+D declared inline after being called", olddecl); + warning ("%J'%D' declared inline after being called", + olddecl, olddecl); warned = true; } else if (DECL_INITIAL (olddecl)) { - warning (0, "%q+D declared inline after its definition", olddecl); + warning ("%J'%D' declared inline after its definition", + olddecl, olddecl); warned = true; } } } else /* PARM_DECL, VAR_DECL */ { - /* Redeclaration of a parameter is a constraint violation (this is - not explicitly stated, but follows from C99 6.7p3 [no more than - one declaration of the same identifier with no linkage in the - same scope, except type tags] and 6.2.2p6 [parameters have no - linkage]). We must check for a forward parameter declaration, - indicated by TREE_ASM_WRITTEN on the old declaration - this is - an extension, the mandatory diagnostic for which is handled by - mark_forward_parm_decls. */ - + /* Redeclaration of a PARM_DECL is invalid unless this is the + real position of a forward-declared parameter (GCC extension). */ if (TREE_CODE (newdecl) == PARM_DECL && (!TREE_ASM_WRITTEN (olddecl) || TREE_ASM_WRITTEN (newdecl))) { - error ("redefinition of parameter %q+D", newdecl); + error ("%Jredefinition of parameter '%D'", newdecl, newdecl); locate_old_decl (olddecl, error); return false; } + + /* These bits are only type qualifiers when applied to objects. */ + if (TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl)) + { + if (TREE_THIS_VOLATILE (newdecl)) + pedwarn ("%Jvolatile declaration of '%D' follows " + "non-volatile declaration", newdecl, newdecl); + else + pedwarn ("%Jnon-volatile declaration of '%D' follows " + "volatile declaration", newdecl, newdecl); + pedwarned = true; + } + if (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)) + { + if (TREE_READONLY (newdecl)) + pedwarn ("%Jconst declaration of '%D' follows " + "non-const declaration", newdecl, newdecl); + else + pedwarn ("%Jnon-const declaration of '%D' follows " + "const declaration", newdecl, newdecl); + pedwarned = true; + } } /* Optional warning for completely redundant decls. */ @@ -1564,11 +1264,11 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, definition. */ && !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl)) - /* Don't warn about redundant redeclarations of builtins. */ + /* Don't warn about redundant redeclarations of builtins. */ && !(TREE_CODE (newdecl) == FUNCTION_DECL && !DECL_BUILT_IN (newdecl) && DECL_BUILT_IN (olddecl) - && !C_DECL_DECLARED_BUILTIN (olddecl)) + && C_DECL_INVISIBLE (olddecl)) /* Don't warn about an extern followed by a definition. */ && !(DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl)) /* Don't warn about forward parameter decls. */ @@ -1578,18 +1278,15 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, && !(TREE_CODE (newdecl) == VAR_DECL && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl))) { - warning (OPT_Wredundant_decls, "redundant redeclaration of %q+D", - newdecl); + warning ("%Jredundant redeclaration of '%D'", newdecl, newdecl); warned = true; } /* Report location of previous decl/defn in a consistent manner. */ if (warned || pedwarned) - locate_old_decl (olddecl, pedwarned ? pedwarn : warning0); - -#undef DECL_EXTERN_INLINE + locate_old_decl (olddecl, pedwarned ? pedwarn : warning); - return retval; + return true; } /* Subroutine of duplicate_decls. NEWDECL has been found to be @@ -1602,43 +1299,26 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) { int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0); - int new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL - && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0); - int old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL - && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0); - - /* For real parm decl following a forward decl, rechain the old decl - in its new location and clear TREE_ASM_WRITTEN (it's not a - forward decl anymore). */ + + /* For real parm decl following a forward decl, return 1 so old decl + will be reused. Only allow this to happen once. */ if (TREE_CODE (newdecl) == PARM_DECL - && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)) + && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl)) { - struct c_binding *b, **here; - - for (here = ¤t_scope->bindings; *here; here = &(*here)->prev) - if ((*here)->decl == olddecl) - goto found; - gcc_unreachable (); - - found: - b = *here; - *here = b->prev; - b->prev = current_scope->bindings; - current_scope->bindings = b; - TREE_ASM_WRITTEN (olddecl) = 0; + return; } DECL_ATTRIBUTES (newdecl) - = targetm.merge_decl_attributes (olddecl, newdecl); + = (*targetm.merge_decl_attributes) (olddecl, newdecl); /* Merge the data types specified in the two decls. */ TREE_TYPE (newdecl) = TREE_TYPE (olddecl) - = composite_type (newtype, oldtype); + = common_type (newtype, oldtype); /* Lay the type out, unless already done. */ - if (!comptypes (oldtype, TREE_TYPE (newdecl))) + if (oldtype != TREE_TYPE (newdecl)) { if (TREE_TYPE (newdecl) != error_mark_node) layout_type (TREE_TYPE (newdecl)); @@ -1661,93 +1341,76 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) } } + /* Keep the old rtl since we can safely use it. */ + COPY_DECL_RTL (olddecl, newdecl); /* Merge the type qualifiers. */ if (TREE_READONLY (newdecl)) TREE_READONLY (olddecl) = 1; if (TREE_THIS_VOLATILE (newdecl)) - TREE_THIS_VOLATILE (olddecl) = 1; - - /* Merge deprecatedness. */ - if (TREE_DEPRECATED (newdecl)) - TREE_DEPRECATED (olddecl) = 1; - - /* Keep source location of definition rather than declaration and of - prototype rather than non-prototype unless that prototype is - built-in. */ - if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0) - || (old_is_prototype && !new_is_prototype - && !C_DECL_BUILTIN_PROTOTYPE (olddecl))) + { + TREE_THIS_VOLATILE (olddecl) = 1; + if (TREE_CODE (newdecl) == VAR_DECL) + make_var_volatile (newdecl); + } + + /* Keep source location of definition rather than declaration. */ + if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0) DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); + /* Merge the unused-warning information. */ + if (DECL_IN_SYSTEM_HEADER (olddecl)) + DECL_IN_SYSTEM_HEADER (newdecl) = 1; + else if (DECL_IN_SYSTEM_HEADER (newdecl)) + DECL_IN_SYSTEM_HEADER (olddecl) = 1; + /* Merge the initialization information. */ if (DECL_INITIAL (newdecl) == 0) DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); - /* Merge the threadprivate attribute. */ - if (TREE_CODE (olddecl) == VAR_DECL && C_DECL_THREADPRIVATE_P (olddecl)) - { - DECL_TLS_MODEL (newdecl) = DECL_TLS_MODEL (olddecl); - C_DECL_THREADPRIVATE_P (newdecl) = 1; - } - - if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS)) - { - /* Merge the unused-warning information. */ - if (DECL_IN_SYSTEM_HEADER (olddecl)) - DECL_IN_SYSTEM_HEADER (newdecl) = 1; - else if (DECL_IN_SYSTEM_HEADER (newdecl)) - DECL_IN_SYSTEM_HEADER (olddecl) = 1; - - /* Merge the section attribute. - We want to issue an error if the sections conflict but that - must be done later in decl_attributes since we are called - before attributes are assigned. */ - if (DECL_SECTION_NAME (newdecl) == NULL_TREE) - DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl); + /* Merge the section attribute. + We want to issue an error if the sections conflict but that must be + done later in decl_attributes since we are called before attributes + are assigned. */ + if (DECL_SECTION_NAME (newdecl) == NULL_TREE) + DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl); - /* Copy the assembler name. - Currently, it can only be defined in the prototype. */ - COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); + /* Copy the assembler name. + Currently, it can only be defined in the prototype. */ + COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); - /* Use visibility of whichever declaration had it specified */ - if (DECL_VISIBILITY_SPECIFIED (olddecl)) - { - DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); - DECL_VISIBILITY_SPECIFIED (newdecl) = 1; - } + /* If either declaration has a nondefault visibility, use it. */ + if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT) + DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); - if (TREE_CODE (newdecl) == FUNCTION_DECL) - { - DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); - DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); - DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl); - DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) - |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); - TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); - TREE_READONLY (newdecl) |= TREE_READONLY (olddecl); - DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl); - DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl); - DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl); - } + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); + DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); + DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl); + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) + |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); + TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); + TREE_READONLY (newdecl) |= TREE_READONLY (olddecl); + DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl); + DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl); + } - /* Merge the storage class information. */ - merge_weak (newdecl, olddecl); + /* Merge the storage class information. */ + merge_weak (newdecl, olddecl); - /* For functions, static overrides non-static. */ - if (TREE_CODE (newdecl) == FUNCTION_DECL) - { - TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl); - /* This is since we don't automatically - copy the attributes of NEWDECL into OLDDECL. */ - TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); - /* If this clears `static', clear it in the identifier too. */ - if (!TREE_PUBLIC (olddecl)) - TREE_PUBLIC (DECL_NAME (olddecl)) = 0; - } + /* For functions, static overrides non-static. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl); + /* This is since we don't automatically + copy the attributes of NEWDECL into OLDDECL. */ + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + /* If this clears `static', clear it in the identifier too. */ + if (! TREE_PUBLIC (olddecl)) + TREE_PUBLIC (DECL_NAME (olddecl)) = 0; } - if (DECL_EXTERNAL (newdecl)) { TREE_STATIC (newdecl) = TREE_STATIC (olddecl); @@ -1755,7 +1418,7 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) /* An extern decl does not override previous storage class. */ TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); - if (!DECL_EXTERNAL (newdecl)) + if (! DECL_EXTERNAL (newdecl)) { DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl); DECL_COMMON (newdecl) = DECL_COMMON (olddecl); @@ -1771,13 +1434,13 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) { /* If we're redefining a function previously defined as extern inline, make sure we emit debug info for the inline before we - throw it away, in case it was inlined into a function that - hasn't been written out yet. */ + throw it away, in case it was inlined into a function that hasn't + been written out yet. */ if (new_is_definition && DECL_INITIAL (olddecl)) { if (TREE_USED (olddecl) /* In unit-at-a-time mode we never inline re-defined extern - inline functions. */ + inline functions. */ && !flag_unit_at_a_time && cgraph_function_possibly_inlined_p (olddecl)) (*debug_hooks->outlining_inline_function) (olddecl); @@ -1788,8 +1451,8 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) } else { - /* If either decl says `inline', this fn is inline, unless - its definition was passed already. */ + /* If either decl says `inline', this fn is inline, + unless its definition was passed already. */ if (DECL_DECLARED_INLINE_P (newdecl) || DECL_DECLARED_INLINE_P (olddecl)) DECL_DECLARED_INLINE_P (newdecl) = 1; @@ -1800,30 +1463,23 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) if (DECL_BUILT_IN (olddecl)) { - /* If redeclaring a builtin function, it stays built in. - But it gets tagged as having been declared. */ + /* If redeclaring a builtin function, it stays built in. */ DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl); DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); - C_DECL_DECLARED_BUILTIN (newdecl) = 1; - if (new_is_prototype) - C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0; - else - C_DECL_BUILTIN_PROTOTYPE (newdecl) - = C_DECL_BUILTIN_PROTOTYPE (olddecl); } /* Also preserve various other info from the definition. */ - if (!new_is_definition) + if (! new_is_definition) { DECL_RESULT (newdecl) = DECL_RESULT (olddecl); DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); - DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl); + DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl); DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl); DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl); /* Set DECL_INLINE on the declaration if we've got a body from which to instantiate. */ - if (DECL_INLINE (olddecl) && !DECL_UNINLINABLE (newdecl)) + if (DECL_INLINE (olddecl) && ! DECL_UNINLINABLE (newdecl)) { DECL_INLINE (newdecl) = 1; DECL_ABSTRACT_ORIGIN (newdecl) @@ -1835,43 +1491,22 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) /* If a previous declaration said inline, mark the definition as inlinable. */ if (DECL_DECLARED_INLINE_P (newdecl) - && !DECL_UNINLINABLE (newdecl)) + && ! DECL_UNINLINABLE (newdecl)) DECL_INLINE (newdecl) = 1; } } /* Copy most of the decl-specific fields of NEWDECL into OLDDECL. - But preserve OLDDECL's DECL_UID and DECL_CONTEXT. */ + But preserve OLDDECL's DECL_UID and C_DECL_INVISIBLE. */ { unsigned olddecl_uid = DECL_UID (olddecl); - tree olddecl_context = DECL_CONTEXT (olddecl); + unsigned olddecl_invisible = C_DECL_INVISIBLE (olddecl); memcpy ((char *) olddecl + sizeof (struct tree_common), (char *) newdecl + sizeof (struct tree_common), - sizeof (struct tree_decl_common) - sizeof (struct tree_common)); - switch (TREE_CODE (olddecl)) - { - case FIELD_DECL: - case VAR_DECL: - case PARM_DECL: - case LABEL_DECL: - case RESULT_DECL: - case CONST_DECL: - case TYPE_DECL: - case FUNCTION_DECL: - memcpy ((char *) olddecl + sizeof (struct tree_decl_common), - (char *) newdecl + sizeof (struct tree_decl_common), - tree_code_size (TREE_CODE (olddecl)) - sizeof (struct tree_decl_common)); - break; - - default: - - memcpy ((char *) olddecl + sizeof (struct tree_decl_common), - (char *) newdecl + sizeof (struct tree_decl_common), - sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common)); - } + sizeof (struct tree_decl) - sizeof (struct tree_common)); DECL_UID (olddecl) = olddecl_uid; - DECL_CONTEXT (olddecl) = olddecl_context; + C_DECL_INVISIBLE (olddecl) = olddecl_invisible; } /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl @@ -1881,7 +1516,7 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) && (TREE_CODE (olddecl) == FUNCTION_DECL || (TREE_CODE (olddecl) == VAR_DECL && TREE_STATIC (olddecl)))) - make_decl_rtl (olddecl); + make_decl_rtl (olddecl, NULL); } /* Handle when a new declaration NEWDECL has the same name as an old @@ -1894,67 +1529,81 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) static bool duplicate_decls (tree newdecl, tree olddecl) { - tree newtype = NULL, oldtype = NULL; + tree newtype, oldtype; if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype)) - { - /* Avoid `unused variable' and other warnings warnings for OLDDECL. */ - TREE_NO_WARNING (olddecl) = 1; - return false; - } + return false; merge_decls (newdecl, olddecl, newtype, oldtype); return true; } - + -/* Check whether decl-node NEW_DECL shadows an existing declaration. */ +/* Return any external DECL associated with ID, whether or not it is + currently in scope. */ + +static tree +any_external_decl (tree id) +{ + tree decl = IDENTIFIER_SYMBOL_VALUE (id); + tree t; + + if (decl == 0 || TREE_CODE (decl) == ERROR_MARK) + return 0; + else if (TREE_CODE (decl) != TYPE_DECL && DECL_EXTERNAL (decl)) + return decl; + + t = purpose_member (id, truly_local_externals); + if (t) + return TREE_VALUE (t); + + return 0; +} + +/* Record an external decl DECL. This only does something if a + shadowing decl already exists. */ static void -warn_if_shadowing (tree new_decl) +record_external_decl (tree decl) { - struct c_binding *b; + tree name = DECL_NAME (decl); + if (!IDENTIFIER_SYMBOL_VALUE (name)) + return; - /* Shadow warnings wanted? */ - if (!warn_shadow + truly_local_externals = tree_cons (name, decl, truly_local_externals); +} + +/* Check whether decl-node X shadows an existing declaration. + OLD is the old IDENTIFIER_SYMBOL_VALUE of the DECL_NAME of X, + which might be a NULL_TREE. */ +static void +warn_if_shadowing (tree x, tree old) +{ + /* Nothing to shadow? */ + if (old == 0 + /* Shadow warnings not wanted? */ + || !warn_shadow /* No shadow warnings for internally generated vars. */ - || DECL_IS_BUILTIN (new_decl) + || DECL_SOURCE_LINE (x) == 0 /* No shadow warnings for vars made for inlining. */ - || DECL_FROM_INLINE (new_decl)) + || DECL_FROM_INLINE (x) + /* Don't warn about the parm names in function declarator + within a function declarator. + It would be nice to avoid warning in any function + declarator in a declaration, as opposed to a definition, + but there is no way to tell it's not a definition. */ + || (TREE_CODE (x) == PARM_DECL && current_scope->outer->parm_flag) + /* Shadow warnings only apply to local variables and parameters. */ + || (TREE_CODE (x) != PARM_DECL && DECL_FILE_SCOPE_P (x))) return; - /* Is anything being shadowed? Invisible decls do not count. */ - for (b = I_SYMBOL_BINDING (DECL_NAME (new_decl)); b; b = b->shadowed) - if (b->decl && b->decl != new_decl && !b->invisible) - { - tree old_decl = b->decl; - - if (old_decl == error_mark_node) - { - warning (OPT_Wshadow, "declaration of %q+D shadows previous " - "non-variable", new_decl); - break; - } - else if (TREE_CODE (old_decl) == PARM_DECL) - warning (OPT_Wshadow, "declaration of %q+D shadows a parameter", - new_decl); - else if (DECL_FILE_SCOPE_P (old_decl)) - warning (OPT_Wshadow, "declaration of %q+D shadows a global " - "declaration", new_decl); - else if (TREE_CODE (old_decl) == FUNCTION_DECL - && DECL_BUILT_IN (old_decl)) - { - warning (OPT_Wshadow, "declaration of %q+D shadows " - "a built-in function", new_decl); - break; - } - else - warning (OPT_Wshadow, "declaration of %q+D shadows a previous local", - new_decl); - - warning (OPT_Wshadow, "%Jshadowed declaration is here", old_decl); + if (TREE_CODE (old) == PARM_DECL) + warning ("%Jdeclaration of '%D' shadows a parameter", x, x); + else if (DECL_FILE_SCOPE_P (old)) + warning ("%Jdeclaration of '%D' shadows a global declaration", x, x); + else + warning ("%Jdeclaration of '%D' shadows a previous local", x, x); - break; - } + warning ("%Jshadowed declaration is here", old); } @@ -1974,7 +1623,7 @@ warn_if_shadowing (tree new_decl) translation and get back the corresponding typedef name. For example, given: - typedef struct S MY_TYPE; + typedef struct S MY_TYPE; MY_TYPE object; Later parts of the compiler might only know that `object' was of @@ -2005,7 +1654,7 @@ warn_if_shadowing (tree new_decl) static void clone_underlying_type (tree x) { - if (DECL_IS_BUILTIN (x)) + if (DECL_SOURCE_LINE (x) == 0) { if (TYPE_NAME (TREE_TYPE (x)) == 0) TYPE_NAME (TREE_TYPE (x)) = x; @@ -2015,7 +1664,7 @@ clone_underlying_type (tree x) { tree tt = TREE_TYPE (x); DECL_ORIGINAL_TYPE (x) = tt; - tt = build_variant_type_copy (tt); + tt = build_type_copy (tt); TYPE_NAME (tt) = x; TREE_USED (tt) = TREE_USED (x); TREE_TYPE (x) = tt; @@ -2035,253 +1684,134 @@ pushdecl (tree x) { tree name = DECL_NAME (x); struct c_scope *scope = current_scope; - struct c_binding *b; - bool nested = false; + +#ifdef ENABLE_CHECKING + if (error_mark_node == 0) + /* Called too early. */ + abort (); +#endif /* Functions need the lang_decl data. */ - if (TREE_CODE (x) == FUNCTION_DECL && !DECL_LANG_SPECIFIC (x)) - DECL_LANG_SPECIFIC (x) = GGC_CNEW (struct lang_decl); - - /* Must set DECL_CONTEXT for everything not at file scope or - DECL_FILE_SCOPE_P won't work. Local externs don't count - unless they have initializers (which generate code). */ - if (current_function_decl - && ((TREE_CODE (x) != FUNCTION_DECL && TREE_CODE (x) != VAR_DECL) - || DECL_INITIAL (x) || !DECL_EXTERNAL (x))) + if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_LANG_SPECIFIC (x)) + DECL_LANG_SPECIFIC (x) = ggc_alloc_cleared (sizeof (struct lang_decl)); + + /* A local extern declaration for a function doesn't constitute nesting. + A local auto declaration does, since it's a forward decl + for a nested function coming later. */ + if (current_function_decl == NULL + || ((TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL) + && DECL_INITIAL (x) == 0 && DECL_EXTERNAL (x))) + DECL_CONTEXT (x) = current_file_decl; + else DECL_CONTEXT (x) = current_function_decl; - /* If this is of variably modified type, prevent jumping into its - scope. */ - if ((TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == TYPE_DECL) - && variably_modified_type_p (TREE_TYPE (x), NULL_TREE)) - c_begin_vm_scope (scope->depth); - - /* Anonymous decls are just inserted in the scope. */ - if (!name) - { - bind (name, x, scope, /*invisible=*/false, /*nested=*/false); - return x; - } - - /* First, see if there is another declaration with the same name in - the current scope. If there is, duplicate_decls may do all the - work for us. If duplicate_decls returns false, that indicates - two incompatible decls in the same scope; we are to silently - replace the old one (duplicate_decls has issued all appropriate - diagnostics). In particular, we should not consider possible - duplicates in the external scope, or shadowing. */ - b = I_SYMBOL_BINDING (name); - if (b && B_IN_SCOPE (b, scope)) - { - struct c_binding *b_ext, *b_use; - tree type = TREE_TYPE (x); - tree visdecl = b->decl; - tree vistype = TREE_TYPE (visdecl); - if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE - && COMPLETE_TYPE_P (TREE_TYPE (x))) - b->inner_comp = false; - b_use = b; - b_ext = b; - /* If this is an external linkage declaration, we should check - for compatibility with the type in the external scope before - setting the type at this scope based on the visible - information only. */ - if (TREE_PUBLIC (x) && TREE_PUBLIC (visdecl)) + if (name) + { + tree old; + + if (warn_nested_externs + && scope != global_scope + && DECL_EXTERNAL (x) + && !DECL_IN_SYSTEM_HEADER (x)) + warning ("nested extern declaration of `%s'", + IDENTIFIER_POINTER (name)); + + old = lookup_name_current_level (name); + if (old && duplicate_decls (x, old)) { - while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext)) - b_ext = b_ext->shadowed; - if (b_ext) + /* For PARM_DECLs, old may be a forward declaration. + If so, we want to remove it from its old location + (in the variables chain) and rechain it in the + location given by the new declaration. */ + if (TREE_CODE (x) == PARM_DECL) { - b_use = b_ext; - if (b_use->type) - TREE_TYPE (b_use->decl) = b_use->type; + tree *p; + for (p = &scope->names; *p; p = &TREE_CHAIN (*p)) + if (*p == old) + { + *p = TREE_CHAIN (old); + SCOPE_LIST_APPEND (scope, parms, old); + break; + } } + return old; } - if (duplicate_decls (x, b_use->decl)) + if (DECL_EXTERNAL (x) || scope == global_scope) { - if (b_use != b) + /* Find and check against a previous, not-in-scope, external + decl for this identifier. (C99 6.2.7p2: All declarations + that refer to the same object or function shall have + compatible type; otherwise, the behavior is undefined.) */ + tree ext = any_external_decl (name); + if (ext) { - /* Save the updated type in the external scope and - restore the proper type for this scope. */ - tree thistype; - if (comptypes (vistype, type)) - thistype = composite_type (vistype, type); - else - thistype = TREE_TYPE (b_use->decl); - b_use->type = TREE_TYPE (b_use->decl); - if (TREE_CODE (b_use->decl) == FUNCTION_DECL - && DECL_BUILT_IN (b_use->decl)) - thistype - = build_type_attribute_variant (thistype, - TYPE_ATTRIBUTES - (b_use->type)); - TREE_TYPE (b_use->decl) = thistype; + if (duplicate_decls (x, ext)) + x = copy_node (ext); } - return b_use->decl; - } - else - goto skip_external_and_shadow_checks; - } - - /* All declarations with external linkage, and all external - references, go in the external scope, no matter what scope is - current. However, the binding in that scope is ignored for - purposes of normal name lookup. A separate binding structure is - created in the requested scope; this governs the normal - visibility of the symbol. - - The binding in the externals scope is used exclusively for - detecting duplicate declarations of the same object, no matter - what scope they are in; this is what we do here. (C99 6.2.7p2: - All declarations that refer to the same object or function shall - have compatible type; otherwise, the behavior is undefined.) */ - if (DECL_EXTERNAL (x) || scope == file_scope) - { - tree type = TREE_TYPE (x); - tree vistype = 0; - tree visdecl = 0; - bool type_saved = false; - if (b && !B_IN_EXTERNAL_SCOPE (b) - && (TREE_CODE (b->decl) == FUNCTION_DECL - || TREE_CODE (b->decl) == VAR_DECL) - && DECL_FILE_SCOPE_P (b->decl)) - { - visdecl = b->decl; - vistype = TREE_TYPE (visdecl); + else + record_external_decl (x); } - if (scope != file_scope - && !DECL_IN_SYSTEM_HEADER (x)) - warning (OPT_Wnested_externs, "nested extern declaration of %qD", x); - while (b && !B_IN_EXTERNAL_SCOPE (b)) - { - /* If this decl might be modified, save its type. This is - done here rather than when the decl is first bound - because the type may change after first binding, through - being completed or through attributes being added. If we - encounter multiple such decls, only the first should have - its type saved; the others will already have had their - proper types saved and the types will not have changed as - their scopes will not have been re-entered. */ - if (DECL_P (b->decl) && DECL_FILE_SCOPE_P (b->decl) && !type_saved) - { - b->type = TREE_TYPE (b->decl); - type_saved = true; - } - if (B_IN_FILE_SCOPE (b) - && TREE_CODE (b->decl) == VAR_DECL - && TREE_STATIC (b->decl) - && TREE_CODE (TREE_TYPE (b->decl)) == ARRAY_TYPE - && !TYPE_DOMAIN (TREE_TYPE (b->decl)) - && TREE_CODE (type) == ARRAY_TYPE - && TYPE_DOMAIN (type) - && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) - && !integer_zerop (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))) - { - /* Array type completed in inner scope, which should be - diagnosed if the completion does not have size 1 and - it does not get completed in the file scope. */ - b->inner_comp = true; - } - b = b->shadowed; - } + if (TREE_CODE (x) == TYPE_DECL) + clone_underlying_type (x); - /* If a matching external declaration has been found, set its - type to the composite of all the types of that declaration. - After the consistency checks, it will be reset to the - composite of the visible types only. */ - if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl)) - && b->type) - TREE_TYPE (b->decl) = b->type; - - /* The point of the same_translation_unit_p check here is, - we want to detect a duplicate decl for a construct like - foo() { extern bar(); } ... static bar(); but not if - they are in different translation units. In any case, - the static does not go in the externals scope. */ - if (b - && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl)) - && duplicate_decls (x, b->decl)) + /* If storing a local value, there may already be one + (inherited). If so, record it for restoration when this + scope ends. Take care not to do this if we are replacing an + older decl in the same scope (i.e. duplicate_decls returned + false, above). */ + if (scope != global_scope) { - tree thistype; - if (vistype) + tree inherited_decl = lookup_name (name); + if (inherited_decl && inherited_decl != old) { - if (comptypes (vistype, type)) - thistype = composite_type (vistype, type); - else - thistype = TREE_TYPE (b->decl); + warn_if_shadowing (x, inherited_decl); + scope->shadowed = tree_cons (name, inherited_decl, + scope->shadowed); } - else - thistype = type; - b->type = TREE_TYPE (b->decl); - if (TREE_CODE (b->decl) == FUNCTION_DECL && DECL_BUILT_IN (b->decl)) - thistype - = build_type_attribute_variant (thistype, - TYPE_ATTRIBUTES (b->type)); - TREE_TYPE (b->decl) = thistype; - bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true); - return b->decl; } - else if (TREE_PUBLIC (x)) + + /* Install the new declaration in the requested scope. */ + IDENTIFIER_SYMBOL_VALUE (name) = x; + C_DECL_INVISIBLE (x) = 0; + + /* If x's type is incomplete because it's based on a + structure or union which has not yet been fully declared, + attach it to that structure or union type, so we can go + back and complete the variable declaration later, if the + structure or union gets fully declared. + + If the input is erroneous, we can have error_mark in the type + slot (e.g. "f(void a, ...)") - that doesn't count as an + incomplete type. */ + if (TREE_TYPE (x) != error_mark_node + && !COMPLETE_TYPE_P (TREE_TYPE (x))) { - if (visdecl && !b && duplicate_decls (x, visdecl)) - { - /* An external declaration at block scope referring to a - visible entity with internal linkage. The composite - type will already be correct for this scope, so we - just need to fall through to make the declaration in - this scope. */ - nested = true; - x = visdecl; - } - else - { - bind (name, x, external_scope, /*invisible=*/true, - /*nested=*/false); - nested = true; - } + tree element = TREE_TYPE (x); + + while (TREE_CODE (element) == ARRAY_TYPE) + element = TREE_TYPE (element); + element = TYPE_MAIN_VARIANT (element); + + if ((TREE_CODE (element) == RECORD_TYPE + || TREE_CODE (element) == UNION_TYPE) + && (TREE_CODE (x) != TYPE_DECL + || TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE) + && !COMPLETE_TYPE_P (element)) + C_TYPE_INCOMPLETE_VARS (element) + = tree_cons (NULL_TREE, x, C_TYPE_INCOMPLETE_VARS (element)); } } - if (TREE_CODE (x) != PARM_DECL) - warn_if_shadowing (x); - - skip_external_and_shadow_checks: - if (TREE_CODE (x) == TYPE_DECL) - clone_underlying_type (x); - - bind (name, x, scope, /*invisible=*/false, nested); - - /* If x's type is incomplete because it's based on a - structure or union which has not yet been fully declared, - attach it to that structure or union type, so we can go - back and complete the variable declaration later, if the - structure or union gets fully declared. - - If the input is erroneous, we can have error_mark in the type - slot (e.g. "f(void a, ...)") - that doesn't count as an - incomplete type. */ - if (TREE_TYPE (x) != error_mark_node - && !COMPLETE_TYPE_P (TREE_TYPE (x))) - { - tree element = TREE_TYPE (x); - - while (TREE_CODE (element) == ARRAY_TYPE) - element = TREE_TYPE (element); - element = TYPE_MAIN_VARIANT (element); + if (TREE_CODE (x) == PARM_DECL) + SCOPE_LIST_APPEND (scope, parms, x); + else + SCOPE_LIST_APPEND (scope, names, x); - if ((TREE_CODE (element) == RECORD_TYPE - || TREE_CODE (element) == UNION_TYPE) - && (TREE_CODE (x) != TYPE_DECL - || TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE) - && !COMPLETE_TYPE_P (element)) - C_TYPE_INCOMPLETE_VARS (element) - = tree_cons (NULL_TREE, x, C_TYPE_INCOMPLETE_VARS (element)); - } return x; } -/* Record X as belonging to file scope. +/* Record X as belonging to the global scope (C99 "file scope"). This is used only internally by the Objective-C front end, and is limited to its needs. duplicate_decls is not called; if there is any preexisting decl for this identifier, it is an ICE. */ @@ -2290,117 +1820,50 @@ tree pushdecl_top_level (tree x) { tree name; - bool nested = false; - gcc_assert (TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == CONST_DECL); + + if (TREE_CODE (x) != VAR_DECL) + abort (); name = DECL_NAME (x); - gcc_assert (TREE_CODE (x) == CONST_DECL || !I_SYMBOL_BINDING (name)); + if (IDENTIFIER_SYMBOL_VALUE (name)) + abort (); - if (TREE_PUBLIC (x)) - { - bind (name, x, external_scope, /*invisible=*/true, /*nested=*/false); - nested = true; - } - if (file_scope) - bind (name, x, file_scope, /*invisible=*/false, nested); + DECL_CONTEXT (x) = current_file_decl; + IDENTIFIER_SYMBOL_VALUE (name) = x; + SCOPE_LIST_APPEND (global_scope, names, x); return x; } -static void -implicit_decl_warning (tree id, tree olddecl) -{ - void (*diag) (const char *, ...) ATTRIBUTE_GCC_CDIAG(1,2); - switch (mesg_implicit_function_declaration) - { - case 0: return; - case 1: diag = warning0; break; - case 2: diag = error; break; - default: gcc_unreachable (); - } - - diag (G_("implicit declaration of function %qE"), id); - if (olddecl) - locate_old_decl (olddecl, diag); -} - /* Generate an implicit declaration for identifier FUNCTIONID as a function of type int (). */ tree implicitly_declare (tree functionid) { - struct c_binding *b; - tree decl = 0; - tree asmspec_tree; - - for (b = I_SYMBOL_BINDING (functionid); b; b = b->shadowed) - { - if (B_IN_SCOPE (b, external_scope)) - { - decl = b->decl; - break; - } - } + tree decl = any_external_decl (functionid); if (decl) { - if (decl == error_mark_node) - return decl; - - /* FIXME: Objective-C has weird not-really-builtin functions - which are supposed to be visible automatically. They wind up - in the external scope because they're pushed before the file - scope gets created. Catch this here and rebind them into the - file scope. */ - if (!DECL_BUILT_IN (decl) && DECL_IS_BUILTIN (decl)) - { - bind (functionid, decl, file_scope, - /*invisible=*/false, /*nested=*/true); - return decl; - } - else + /* Implicit declaration of a function already declared + (somehow) in a different scope, or as a built-in. + If this is the first time this has happened, warn; + then recycle the old declaration. */ + if (!C_DECL_IMPLICIT (decl)) { - tree newtype = default_function_type; - if (b->type) - TREE_TYPE (decl) = b->type; - /* Implicit declaration of a function already declared - (somehow) in a different scope, or as a built-in. - If this is the first time this has happened, warn; - then recycle the old declaration but with the new type. */ - if (!C_DECL_IMPLICIT (decl)) - { - implicit_decl_warning (functionid, decl); - C_DECL_IMPLICIT (decl) = 1; - } - if (DECL_BUILT_IN (decl)) - { - newtype = build_type_attribute_variant (newtype, - TYPE_ATTRIBUTES - (TREE_TYPE (decl))); - if (!comptypes (newtype, TREE_TYPE (decl))) - { - warning (0, "incompatible implicit declaration of built-in" - " function %qD", decl); - newtype = TREE_TYPE (decl); - } - } - else - { - if (!comptypes (newtype, TREE_TYPE (decl))) - { - error ("incompatible implicit declaration of function %qD", - decl); - locate_old_decl (decl, error); - } - } - b->type = TREE_TYPE (decl); - TREE_TYPE (decl) = newtype; - bind (functionid, decl, current_scope, - /*invisible=*/false, /*nested=*/true); - return decl; + implicit_decl_warning (DECL_NAME (decl)); + if (! DECL_FILE_SCOPE_P (decl)) + warning ("%Jprevious declaration of '%D'", decl, decl); + C_DECL_IMPLICIT (decl) = 1; } + /* If this function is global, then it must already be in the + global scope, so there's no need to push it again. */ + if (current_scope == global_scope) + return decl; + /* If this is a local declaration, make a copy; we can't have + the same DECL listed in two different scopes. */ + return pushdecl (copy_node (decl)); } /* Not seen before. */ @@ -2408,17 +1871,14 @@ implicitly_declare (tree functionid) DECL_EXTERNAL (decl) = 1; TREE_PUBLIC (decl) = 1; C_DECL_IMPLICIT (decl) = 1; - implicit_decl_warning (functionid, 0); - asmspec_tree = maybe_apply_renaming_pragma (decl, /*asmname=*/NULL); - if (asmspec_tree) - set_user_assembler_name (decl, TREE_STRING_POINTER (asmspec_tree)); + implicit_decl_warning (functionid); /* C89 says implicit declarations are in the innermost block. So we record the decl in the standard fashion. */ decl = pushdecl (decl); /* No need to call objc_check_decl here - it's a function type. */ - rest_of_decl_compilation (decl, 0, 0); + rest_of_decl_compilation (decl, NULL, 0, 0); /* Write a record describing this implicit function declaration to the prototypes file (if requested). */ @@ -2430,38 +1890,51 @@ implicitly_declare (tree functionid) return decl; } +static void +implicit_decl_warning (tree id) +{ + const char *name = IDENTIFIER_POINTER (id); + if (mesg_implicit_function_declaration == 2) + error ("implicit declaration of function `%s'", name); + else if (mesg_implicit_function_declaration == 1) + warning ("implicit declaration of function `%s'", name); +} + /* Issue an error message for a reference to an undeclared variable ID, including a reference to a builtin outside of function-call context. Establish a binding of the identifier to error_mark_node in an appropriate scope, which will suppress further errors for the - same identifier. The error message should be given location LOC. */ + same identifier. */ void -undeclared_variable (tree id, location_t loc) +undeclared_variable (tree id) { static bool already = false; struct c_scope *scope; if (current_function_decl == 0) { - error ("%H%qE undeclared here (not in a function)", &loc, id); + error ("`%s' undeclared here (not in a function)", + IDENTIFIER_POINTER (id)); scope = current_scope; } else { - error ("%H%qE undeclared (first use in this function)", &loc, id); + error ("`%s' undeclared (first use in this function)", + IDENTIFIER_POINTER (id)); - if (!already) + if (! already) { - error ("%H(Each undeclared identifier is reported only once", &loc); - error ("%Hfor each function it appears in.)", &loc); + error ("(Each undeclared identifier is reported only once"); + error ("for each function it appears in.)"); already = true; } - /* If we are parsing old-style parameter decls, current_function_decl - will be nonnull but current_function_scope will be null. */ - scope = current_function_scope ? current_function_scope : current_scope; + scope = current_function_scope; } - bind (id, error_mark_node, scope, /*invisible=*/false, /*nested=*/false); + + scope->shadowed = tree_cons (id, IDENTIFIER_SYMBOL_VALUE (id), + scope->shadowed); + IDENTIFIER_SYMBOL_VALUE (id) = error_mark_node; } /* Subroutine of lookup_label, declare_label, define_label: construct a @@ -2479,6 +1952,20 @@ make_label (tree name, location_t location) return label; } +/* Another subroutine of lookup_label, declare_label, define_label: + set up the binding of name to LABEL_DECL in the given SCOPE. */ + +static void +bind_label (tree name, tree label, struct c_scope *scope) +{ + if (IDENTIFIER_LABEL_VALUE (name)) + scope->shadowed = tree_cons (name, IDENTIFIER_LABEL_VALUE (name), + scope->shadowed); + IDENTIFIER_LABEL_VALUE (name) = label; + + SCOPE_LIST_APPEND (scope, names, label); +} + /* Get the LABEL_DECL corresponding to identifier NAME as a label. Create one if none exists so far for the current function. This is called when a label is used in a goto expression or @@ -2491,14 +1978,15 @@ lookup_label (tree name) if (current_function_decl == 0) { - error ("label %qE referenced outside of any function", name); + error ("label %s referenced outside of any function", + IDENTIFIER_POINTER (name)); return 0; } /* Use a label already defined or ref'd with this name, but not if it is inherited from a containing function and wasn't declared using __label__. */ - label = I_LABEL_DECL (name); + label = IDENTIFIER_LABEL_VALUE (name); if (label && (DECL_CONTEXT (label) == current_function_decl || C_DECLARED_LABEL_FLAG (label))) { @@ -2514,8 +2002,7 @@ lookup_label (tree name) label = make_label (name, input_location); /* Ordinary labels go in the current function scope. */ - bind (name, label, current_function_scope, - /*invisible=*/false, /*nested=*/false); + bind_label (name, label, current_function_scope); return label; } @@ -2523,29 +2010,33 @@ lookup_label (tree name) any that may be inherited from containing functions or containing scopes. This is called for __label__ declarations. */ +/* Note that valid use, if the label being shadowed comes from another + scope in the same function, requires calling declare_nonlocal_label + right away. (Is this still true? -zw 2003-07-17) */ + tree declare_label (tree name) { - struct c_binding *b = I_LABEL_BINDING (name); - tree label; + tree label = IDENTIFIER_LABEL_VALUE (name); + tree dup; /* Check to make sure that the label hasn't already been declared at this scope */ - if (b && B_IN_CURRENT_SCOPE (b)) - { - error ("duplicate label declaration %qE", name); - locate_old_decl (b->decl, error); + for (dup = current_scope->names; dup; dup = TREE_CHAIN (dup)) + if (dup == label) + { + error ("duplicate label declaration `%s'", IDENTIFIER_POINTER (name)); + error ("%Jthis is a previous declaration", dup); - /* Just use the previous declaration. */ - return b->decl; - } + /* Just use the previous declaration. */ + return dup; + } label = make_label (name, input_location); C_DECLARED_LABEL_FLAG (label) = 1; /* Declared labels go in the current scope. */ - bind (name, label, current_scope, - /*invisible=*/false, /*nested=*/false); + bind_label (name, label, current_scope); return label; } @@ -2556,12 +2047,13 @@ declare_label (tree name) tree define_label (location_t location, tree name) { + tree label; + /* Find any preexisting label with this name. It is an error if that label has already been defined in this function, or if there is a containing function with a declared label with the same name. */ - tree label = I_LABEL_DECL (name); - struct c_label_list *nlist_se, *nlist_vm; + label = IDENTIFIER_LABEL_VALUE (name); if (label && ((DECL_CONTEXT (label) == current_function_decl @@ -2569,8 +2061,11 @@ define_label (location_t location, tree name) || (DECL_CONTEXT (label) != current_function_decl && C_DECLARED_LABEL_FLAG (label)))) { - error ("%Hduplicate label %qD", &location, label); - locate_old_decl (label, error); + error ("%Hduplicate label `%D'", &location, label); + if (DECL_INITIAL (label)) + error ("%J`%D' previously defined here", label, label); + else + error ("%J`%D' previously declared here", label, label); return 0; } else if (label && DECL_CONTEXT (label) == current_function_decl) @@ -2578,11 +2073,6 @@ define_label (location_t location, tree name) /* The label has been used or declared already in this function, but not defined. Update its location to point to this definition. */ - if (C_DECL_UNDEFINABLE_STMT_EXPR (label)) - error ("%Jjump into statement expression", label); - if (C_DECL_UNDEFINABLE_VM (label)) - error ("%Jjump into scope of identifier with variably modified type", - label); DECL_SOURCE_LOCATION (label) = location; } else @@ -2591,29 +2081,28 @@ define_label (location_t location, tree name) label = make_label (name, location); /* Ordinary labels go in the current function scope. */ - bind (name, label, current_function_scope, - /*invisible=*/false, /*nested=*/false); + bind_label (name, label, current_function_scope); } - if (!in_system_header && lookup_name (name)) - warning (OPT_Wtraditional, "%Htraditional C lacks a separate namespace " - "for labels, identifier %qE conflicts", &location, name); - - nlist_se = XOBNEW (&parser_obstack, struct c_label_list); - nlist_se->next = label_context_stack_se->labels_def; - nlist_se->label = label; - label_context_stack_se->labels_def = nlist_se; - - nlist_vm = XOBNEW (&parser_obstack, struct c_label_list); - nlist_vm->next = label_context_stack_vm->labels_def; - nlist_vm->label = label; - label_context_stack_vm->labels_def = nlist_vm; + if (warn_traditional && !in_system_header && lookup_name (name)) + warning ("%Htraditional C lacks a separate namespace for labels, " + "identifier `%s' conflicts", &location, + IDENTIFIER_POINTER (name)); /* Mark label as having been defined. */ DECL_INITIAL (label) = error_mark_node; return label; } +/* Return the list of declarations of the current scope. */ + +tree +getdecls (void) +{ + return current_scope->names; +} + + /* Given NAME, an IDENTIFIER_NODE, return the structure (or union or enum) definition for that name. If THISLEVEL_ONLY is nonzero, searches only the current_scope. @@ -2624,29 +2113,25 @@ define_label (location_t location, tree name) static tree lookup_tag (enum tree_code code, tree name, int thislevel_only) { - struct c_binding *b = I_TAG_BINDING (name); + tree tag = IDENTIFIER_TAG_VALUE (name); int thislevel = 0; - if (!b || !b->decl) + if (!tag) return 0; /* We only care about whether it's in this level if thislevel_only was set or it might be a type clash. */ - if (thislevel_only || TREE_CODE (b->decl) != code) - { - /* For our purposes, a tag in the external scope is the same as - a tag in the file scope. (Primarily relevant to Objective-C - and its builtin structure tags, which get pushed before the - file scope is created.) */ - if (B_IN_CURRENT_SCOPE (b) - || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) + if (thislevel_only || TREE_CODE (tag) != code) + { + if (current_scope == global_scope + || purpose_member (name, current_scope->tags)) thislevel = 1; } if (thislevel_only && !thislevel) return 0; - if (TREE_CODE (b->decl) != code) + if (TREE_CODE (tag) != code) { /* Definition isn't the kind we were looking for. */ pending_invalid_xref = name; @@ -2659,7 +2144,7 @@ lookup_tag (enum tree_code code, tree name, int thislevel_only) if (thislevel) pending_xref_error (); } - return b->decl; + return tag; } /* Print an error message now @@ -2671,8 +2156,9 @@ void pending_xref_error (void) { if (pending_invalid_xref != 0) - error ("%H%qE defined as wrong kind of tag", - &pending_invalid_xref_location, pending_invalid_xref); + error ("%H`%s' defined as wrong kind of tag", + &pending_invalid_xref_location, + IDENTIFIER_POINTER (pending_invalid_xref)); pending_invalid_xref = 0; } @@ -2685,22 +2171,36 @@ pending_xref_error (void) tree lookup_name (tree name) { - struct c_binding *b = I_SYMBOL_BINDING (name); - if (b && !b->invisible) - return b->decl; - return 0; + tree decl = IDENTIFIER_SYMBOL_VALUE (name); + if (decl == 0 || decl == error_mark_node) + return decl; + if (C_DECL_INVISIBLE (decl)) + return 0; + return decl; } -/* Similar to `lookup_name' but look only at the indicated scope. */ +/* Similar to `lookup_name' but look only at the current scope. */ static tree -lookup_name_in_scope (tree name, struct c_scope *scope) +lookup_name_current_level (tree name) { - struct c_binding *b; + tree decl = IDENTIFIER_SYMBOL_VALUE (name); + + if (decl == 0 || decl == error_mark_node || C_DECL_INVISIBLE (decl)) + return 0; + + if (current_scope == global_scope) + return decl; + + /* Scan the current scope for a decl with name NAME. + For PARM_DECLs, we have to look at both ->parms and ->names, since + forward parameter declarations wind up on the ->names list. */ + if (TREE_CODE (decl) == PARM_DECL + && chain_member (decl, current_scope->parms)) + return decl; + if (chain_member (decl, current_scope->names)) + return decl; - for (b = I_SYMBOL_BINDING (name); b; b = b->shadowed) - if (B_IN_SCOPE (b, scope)) - return b->decl; return 0; } @@ -2712,30 +2212,29 @@ lookup_name_in_scope (tree name, struct c_scope *scope) void c_init_decl_processing (void) { + tree endlink; + tree ptr_ftype_void, ptr_ftype_ptr; location_t save_loc = input_location; - /* Initialize reserved words for parser. */ + /* Adds some ggc roots, and reserved words for c-parse.in. */ c_parse_init (); current_function_decl = 0; - gcc_obstack_init (&parser_obstack); - - /* Make the externals scope. */ - push_scope (); - external_scope = current_scope; + /* Make the c_scope structure for global names. */ + pushlevel (0); + global_scope = current_scope; /* Declarations from c_common_nodes_and_builtins must not be associated with this input file, lest we get differences between using and not using preprocessed headers. */ -#ifdef USE_MAPPED_LOCATION - input_location = BUILTINS_LOCATION; -#else - input_location.file = "<built-in>"; + input_location.file = "<internal>"; input_location.line = 0; -#endif - build_common_tree_nodes (flag_signed_char, false); + /* Make the DECL for the toplevel file scope. */ + current_file_decl = build_decl (TRANSLATION_UNIT_DECL, NULL, NULL); + + build_common_tree_nodes (flag_signed_char); c_common_nodes_and_builtins (); @@ -2748,12 +2247,21 @@ c_init_decl_processing (void) pushdecl (build_decl (TYPE_DECL, get_identifier ("_Bool"), boolean_type_node)); + endlink = void_list_node; + ptr_ftype_void = build_function_type (ptr_type_node, endlink); + ptr_ftype_ptr + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, endlink)); + input_location = save_loc; - pedantic_lvalues = true; + pedantic_lvalues = pedantic; make_fname_decl = c_make_fname_decl; start_fname_decls (); + + first_builtin_decl = global_scope->names; + last_builtin_decl = global_scope->names_last; } /* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the @@ -2770,9 +2278,9 @@ c_make_fname_decl (tree id, int type_dep) tree decl, type, init; size_t length = strlen (name); - type = build_array_type (char_type_node, - build_index_type (size_int (length))); - type = c_build_qualified_type (type, TYPE_QUAL_CONST); + type = build_array_type + (build_qualified_type (char_type_node, TYPE_QUAL_CONST), + build_index_type (size_int (length))); decl = build_decl (VAR_DECL, id, type); @@ -2781,26 +2289,16 @@ c_make_fname_decl (tree id, int type_dep) DECL_ARTIFICIAL (decl) = 1; init = build_string (length + 1, name); - free ((char *) name); TREE_TYPE (init) = type; DECL_INITIAL (decl) = init; TREE_USED (decl) = 1; - if (current_function_decl - /* For invalid programs like this: - - void foo() - const char* p = __FUNCTION__; - - the __FUNCTION__ is believed to appear in K&R style function - parameter declarator. In that case we still don't have - function_scope. */ - && (!errorcount || current_function_scope)) + if (current_function_decl) { DECL_CONTEXT (decl) = current_function_decl; - bind (id, decl, current_function_scope, - /*invisible=*/false, /*nested=*/false); + IDENTIFIER_SYMBOL_VALUE (id) = decl; + SCOPE_LIST_APPEND (current_function_scope, names, decl); } finish_decl (decl, init, NULL_TREE); @@ -2819,32 +2317,23 @@ c_make_fname_decl (tree id, int type_dep) tree builtin_function (const char *name, tree type, int function_code, - enum built_in_class cl, const char *library_name, + enum built_in_class class, const char *library_name, tree attrs) { - tree id = get_identifier (name); - tree decl = build_decl (FUNCTION_DECL, id, type); - TREE_PUBLIC (decl) = 1; + tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type); DECL_EXTERNAL (decl) = 1; - DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl); - DECL_BUILT_IN_CLASS (decl) = cl; - DECL_FUNCTION_CODE (decl) = function_code; - C_DECL_BUILTIN_PROTOTYPE (decl) = (TYPE_ARG_TYPES (type) != 0); + TREE_PUBLIC (decl) = 1; if (library_name) SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name)); + make_decl_rtl (decl, NULL); + pushdecl (decl); + DECL_BUILT_IN_CLASS (decl) = class; + DECL_FUNCTION_CODE (decl) = function_code; - /* Should never be called on a symbol with a preexisting meaning. */ - gcc_assert (!I_SYMBOL_BINDING (id)); - - bind (id, decl, external_scope, /*invisible=*/true, /*nested=*/false); - - /* Builtins in the implementation namespace are made visible without - needing to be explicitly declared. See push_file_scope. */ - if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1]))) - { - TREE_CHAIN (decl) = visible_builtins; - visible_builtins = decl; - } + /* Warn if a function in the namespace for users + is used without an occasion to consider it declared. */ + if (name[0] != '_' || name[1] != '_') + C_DECL_INVISIBLE (decl) = 1; /* Possibly apply some default attributes to this built-in function. */ if (attrs) @@ -2864,21 +2353,31 @@ builtin_function (const char *name, tree type, int function_code, Otherwise, it is an error. */ void -shadow_tag (const struct c_declspecs *declspecs) +shadow_tag (tree declspecs) { shadow_tag_warned (declspecs, 0); } -/* WARNED is 1 if we have done a pedwarn, 2 if we have done a warning, - but no pedwarn. */ void -shadow_tag_warned (const struct c_declspecs *declspecs, int warned) +shadow_tag_warned (tree declspecs, int warned) + + + /* 1 => we have done a pedwarn. 2 => we have done a warning, but + no pedwarn. */ { - bool found_tag = false; + int found_tag = 0; + tree link; + tree specs, attrs; - if (declspecs->type && !declspecs->default_int_p && !declspecs->typedef_p) + pending_invalid_xref = 0; + + /* Remove the attributes from declspecs, since they will confuse the + following code. */ + split_specs_attrs (declspecs, &specs, &attrs); + + for (link = specs; link; link = TREE_CHAIN (link)) { - tree value = declspecs->type; + tree value = TREE_VALUE (link); enum tree_code code = TREE_CODE (value); if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) @@ -2888,7 +2387,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) tree name = TYPE_NAME (value); tree t; - found_tag = true; + found_tag++; if (name == 0) { @@ -2899,29 +2398,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) warned = 1; } } - else if (!declspecs->tag_defined_p - && declspecs->storage_class != csc_none) - { - if (warned != 1) - pedwarn ("empty declaration with storage class specifier " - "does not redeclare tag"); - warned = 1; - pending_xref_error (); - } - else if (!declspecs->tag_defined_p - && (declspecs->const_p - || declspecs->volatile_p - || declspecs->restrict_p)) - { - if (warned != 1) - pedwarn ("empty declaration with type qualifier " - "does not redeclare tag"); - warned = 1; - pending_xref_error (); - } else { - pending_invalid_xref = 0; t = lookup_tag (code, name, 1); if (t == 0) @@ -2933,210 +2411,102 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) } else { - if (warned != 1 && !in_system_header) + if (!warned && ! in_system_header) { - pedwarn ("useless type name in empty declaration"); - warned = 1; + warning ("useless keyword or type name in empty declaration"); + warned = 2; } } } - else if (warned != 1 && !in_system_header && declspecs->typedef_p) - { - pedwarn ("useless type name in empty declaration"); - warned = 1; - } - pending_invalid_xref = 0; - - if (declspecs->inline_p) - { - error ("%<inline%> in empty declaration"); - warned = 1; - } - - if (current_scope == file_scope && declspecs->storage_class == csc_auto) - { - error ("%<auto%> in file-scope empty declaration"); - warned = 1; - } - - if (current_scope == file_scope && declspecs->storage_class == csc_register) - { - error ("%<register%> in file-scope empty declaration"); - warned = 1; - } - - if (!warned && !in_system_header && declspecs->storage_class != csc_none) - { - warning (0, "useless storage class specifier in empty declaration"); - warned = 2; - } - - if (!warned && !in_system_header && declspecs->thread_p) - { - warning (0, "useless %<__thread%> in empty declaration"); - warned = 2; - } - - if (!warned && !in_system_header && (declspecs->const_p - || declspecs->volatile_p - || declspecs->restrict_p)) - { - warning (0, "useless type qualifier in empty declaration"); - warned = 2; - } + if (found_tag > 1) + error ("two types specified in one empty declaration"); if (warned != 1) { - if (!found_tag) + if (found_tag == 0) pedwarn ("empty declaration"); } } +/* Construct an array declarator. EXPR is the expression inside [], or + NULL_TREE. QUALS are the type qualifiers inside the [] (to be applied + to the pointer to which a parameter array is converted). STATIC_P is + nonzero if "static" is inside the [], zero otherwise. VLA_UNSPEC_P + is nonzero is the array is [*], a VLA of unspecified length which is + nevertheless a complete type (not currently implemented by GCC), + zero otherwise. The declarator is constructed as an ARRAY_REF + (to be decoded by grokdeclarator), whose operand 0 is what's on the + left of the [] (filled by in set_array_declarator_type) and operand 1 + is the expression inside; whose TREE_TYPE is the type qualifiers and + which has TREE_STATIC set if "static" is used. */ -/* Return the qualifiers from SPECS as a bitwise OR of TYPE_QUAL_* - bits. SPECS represents declaration specifiers that the grammar - only permits to contain type qualifiers and attributes. */ - -int -quals_from_declspecs (const struct c_declspecs *specs) -{ - int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0) - | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0) - | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0)); - gcc_assert (!specs->type - && !specs->decl_attr - && specs->typespec_word == cts_none - && specs->storage_class == csc_none - && !specs->typedef_p - && !specs->explicit_signed_p - && !specs->deprecated_p - && !specs->long_p - && !specs->long_long_p - && !specs->short_p - && !specs->signed_p - && !specs->unsigned_p - && !specs->complex_p - && !specs->inline_p - && !specs->thread_p); - return quals; -} - -/* Construct an array declarator. EXPR is the expression inside [], - or NULL_TREE. QUALS are the type qualifiers inside the [] (to be - applied to the pointer to which a parameter array is converted). - STATIC_P is true if "static" is inside the [], false otherwise. - VLA_UNSPEC_P is true if the array is [*], a VLA of unspecified - length which is nevertheless a complete type, false otherwise. The - field for the contained declarator is left to be filled in by - set_array_declarator_inner. */ - -struct c_declarator * -build_array_declarator (tree expr, struct c_declspecs *quals, bool static_p, - bool vla_unspec_p) +tree +build_array_declarator (tree expr, tree quals, int static_p, int vla_unspec_p) { - struct c_declarator *declarator = XOBNEW (&parser_obstack, - struct c_declarator); - declarator->kind = cdk_array; - declarator->declarator = 0; - declarator->u.array.dimen = expr; - if (quals) - { - declarator->u.array.attrs = quals->attrs; - declarator->u.array.quals = quals_from_declspecs (quals); - } - else - { - declarator->u.array.attrs = NULL_TREE; - declarator->u.array.quals = 0; - } - declarator->u.array.static_p = static_p; - declarator->u.array.vla_unspec_p = vla_unspec_p; + tree decl; + decl = build_nt (ARRAY_REF, NULL_TREE, expr); + TREE_TYPE (decl) = quals; + TREE_STATIC (decl) = (static_p ? 1 : 0); if (pedantic && !flag_isoc99) { - if (static_p || quals != NULL) - pedwarn ("ISO C90 does not support %<static%> or type " - "qualifiers in parameter array declarators"); + if (static_p || quals != NULL_TREE) + pedwarn ("ISO C90 does not support `static' or type qualifiers in parameter array declarators"); if (vla_unspec_p) - pedwarn ("ISO C90 does not support %<[*]%> array declarators"); + pedwarn ("ISO C90 does not support `[*]' array declarators"); } if (vla_unspec_p) - { - if (!current_scope->parm_flag) - { - /* C99 6.7.5.2p4 */ - error ("%<[*]%> not allowed in other than function prototype scope"); - declarator->u.array.vla_unspec_p = false; - return NULL; - } - current_scope->had_vla_unspec = true; - } - return declarator; + warning ("GCC does not yet properly implement `[*]' array declarators"); + return decl; } -/* Set the contained declarator of an array declarator. DECL is the - declarator, as constructed by build_array_declarator; INNER is what - appears on the left of the []. ABSTRACT_P is true if it is an - abstract declarator, false otherwise; this is used to reject static - and type qualifiers in abstract declarators, where they are not in - the C99 grammar (subject to possible change in DR#289). */ +/* Set the type of an array declarator. DECL is the declarator, as + constructed by build_array_declarator; TYPE is what appears on the left + of the [] and goes in operand 0. ABSTRACT_P is nonzero if it is an + abstract declarator, zero otherwise; this is used to reject static and + type qualifiers in abstract declarators, where they are not in the + C99 grammar. */ -struct c_declarator * -set_array_declarator_inner (struct c_declarator *decl, - struct c_declarator *inner, bool abstract_p) +tree +set_array_declarator_type (tree decl, tree type, int abstract_p) { - decl->declarator = inner; - if (abstract_p && (decl->u.array.quals != TYPE_UNQUALIFIED - || decl->u.array.attrs != NULL_TREE - || decl->u.array.static_p)) + TREE_OPERAND (decl, 0) = type; + if (abstract_p && (TREE_TYPE (decl) != NULL_TREE || TREE_STATIC (decl))) error ("static or type qualifiers in abstract declarator"); return decl; } - -/* INIT is a constructor that forms DECL's initializer. If the final - element initializes a flexible array field, add the size of that - initializer to DECL's size. */ - -static void -add_flexible_array_elts_to_size (tree decl, tree init) -{ - tree elt, type; - - if (VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (init))) - return; - - elt = VEC_last (constructor_elt, CONSTRUCTOR_ELTS (init))->value; - type = TREE_TYPE (elt); - if (TREE_CODE (type) == ARRAY_TYPE - && TYPE_SIZE (type) == NULL_TREE - && TYPE_DOMAIN (type) != NULL_TREE - && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE) - { - complete_array_type (&type, elt, false); - DECL_SIZE (decl) - = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type)); - DECL_SIZE_UNIT (decl) - = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type)); - } -} /* Decode a "typename", such as "int **", returning a ..._TYPE node. */ tree -groktypename (struct c_type_name *type_name) +groktypename (tree typename) { - tree type; - tree attrs = type_name->specs->attrs; + tree specs, attrs; - type_name->specs->attrs = NULL_TREE; + if (TREE_CODE (typename) != TREE_LIST) + return typename; - type = grokdeclarator (type_name->declarator, type_name->specs, TYPENAME, - false, NULL); + split_specs_attrs (TREE_PURPOSE (typename), &specs, &attrs); + + typename = grokdeclarator (TREE_VALUE (typename), specs, TYPENAME, 0, + NULL); /* Apply attributes. */ - decl_attributes (&type, attrs, 0); + decl_attributes (&typename, attrs, 0); + + return typename; +} - return type; +/* Return a PARM_DECL node for a given pair of specs and declarator. */ + +tree +groktypename_in_parm_context (tree typename) +{ + if (TREE_CODE (typename) != TREE_LIST) + return typename; + return grokdeclarator (TREE_VALUE (typename), + TREE_PURPOSE (typename), + PARM, 0, NULL); } /* Decode a declarator in an ordinary declaration or data definition. @@ -3155,8 +2525,7 @@ groktypename (struct c_type_name *type_name) grokfield and not through here. */ tree -start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, - bool initialized, tree attributes) +start_decl (tree declarator, tree declspecs, int initialized, tree attributes) { tree decl; tree tem; @@ -3168,43 +2537,44 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, NULL); - if (!decl) - return 0; deprecated_state = DEPRECATED_NORMAL; if (warn_main > 0 && TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl))) - warning (OPT_Wmain, "%q+D is usually a function", decl); + warning ("%J'%D' is usually a function", decl, decl); if (initialized) /* Is it valid for this decl to have an initializer at all? If not, set INITIALIZED to zero, which will indirectly - tell 'finish_decl' to ignore the initializer once it is parsed. */ + tell `finish_decl' to ignore the initializer once it is parsed. */ switch (TREE_CODE (decl)) { case TYPE_DECL: - error ("typedef %qD is initialized (use __typeof__ instead)", decl); + error ("typedef `%s' is initialized (use __typeof__ instead)", + IDENTIFIER_POINTER (DECL_NAME (decl))); initialized = 0; break; case FUNCTION_DECL: - error ("function %qD is initialized like a variable", decl); + error ("function `%s' is initialized like a variable", + IDENTIFIER_POINTER (DECL_NAME (decl))); initialized = 0; break; case PARM_DECL: /* DECL_INITIAL in a PARM_DECL is really DECL_ARG_TYPE. */ - error ("parameter %qD is initialized", decl); + error ("parameter `%s' is initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); initialized = 0; break; default: - /* Don't allow initializations for incomplete types except for - arrays which might be completed by the initialization. */ + /* Don't allow initializations for incomplete types + except for arrays which might be completed by the initialization. */ - /* This can happen if the array size is an undefined macro. - We already gave a warning, so we don't need another one. */ + /* This can happen if the array size is an undefined macro. We already + gave a warning, so we don't need another one. */ if (TREE_TYPE (decl) == error_mark_node) initialized = 0; else if (COMPLETE_TYPE_P (TREE_TYPE (decl))) @@ -3220,28 +2590,27 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, } else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) { - error ("variable %qD has initializer but incomplete type", decl); + error ("variable `%s' has initializer but incomplete type", + IDENTIFIER_POINTER (DECL_NAME (decl))); initialized = 0; } - else if (C_DECL_VARIABLE_SIZE (decl)) + else if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (decl)))) { - /* Although C99 is unclear about whether incomplete arrays - of VLAs themselves count as VLAs, it does not make - sense to permit them to be initialized given that - ordinary VLAs may not be initialized. */ - error ("variable-sized object may not be initialized"); + error ("elements of array `%s' have incomplete type", + IDENTIFIER_POINTER (DECL_NAME (decl))); initialized = 0; } } if (initialized) { - if (current_scope == file_scope) + DECL_EXTERNAL (decl) = 0; + if (current_scope == global_scope) TREE_STATIC (decl) = 1; - /* Tell 'pushdecl' this is an initialized decl + /* Tell `pushdecl' this is an initialized decl even though we don't yet have the initializer expression. - Also tell 'finish_decl' it may store the real initializer. */ + Also tell `finish_decl' it may store the real initializer. */ DECL_INITIAL (decl) = error_mark_node; } @@ -3265,7 +2634,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, if (TREE_CODE (decl) == VAR_DECL && !initialized && TREE_PUBLIC (decl) - && !DECL_THREAD_LOCAL_P (decl) + && !DECL_THREAD_LOCAL (decl) && !flag_no_common) DECL_COMMON (decl) = 1; @@ -3275,17 +2644,17 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, if (TREE_CODE (decl) == FUNCTION_DECL && targetm.calls.promote_prototypes (TREE_TYPE (decl))) { - struct c_declarator *ce = declarator; + tree ce = declarator; - if (ce->kind == cdk_pointer) - ce = declarator->declarator; - if (ce->kind == cdk_function) + if (TREE_CODE (ce) == INDIRECT_REF) + ce = TREE_OPERAND (declarator, 0); + if (TREE_CODE (ce) == CALL_EXPR) { - tree args = ce->u.arg_info->parms; + tree args = TREE_PURPOSE (TREE_OPERAND (ce, 1)); for (; args; args = TREE_CHAIN (args)) { tree type = TREE_TYPE (args); - if (type && INTEGRAL_TYPE_P (type) + if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) DECL_ARG_TYPE (args) = integer_type_node; } @@ -3296,39 +2665,30 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, && DECL_DECLARED_INLINE_P (decl) && DECL_UNINLINABLE (decl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl))) - warning (OPT_Wattributes, "inline function %q+D given attribute noinline", - decl); + warning ("%Jinline function '%D' given attribute noinline", decl, decl); /* Add this decl to the current scope. TEM may equal DECL or it may be a previous decl of the same name. */ tem = pushdecl (decl); - if (initialized && DECL_EXTERNAL (tem)) + /* For a local variable, define the RTL now. */ + if (current_scope != global_scope + /* But not if this is a duplicate decl + and we preserved the rtl from the previous one + (which may or may not happen). */ + && !DECL_RTL_SET_P (tem) + && DECL_FILE_SCOPE_P (tem)) { - DECL_EXTERNAL (tem) = 0; - TREE_STATIC (tem) = 1; + if (TREE_TYPE (tem) != error_mark_node + && (COMPLETE_TYPE_P (TREE_TYPE (tem)) + || (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE + && DECL_INITIAL (tem) != 0))) + expand_decl (tem); } return tem; } -/* Initialize EH if not initialized yet and exceptions are enabled. */ - -void -c_maybe_initialize_eh (void) -{ - if (!flag_exceptions || c_eh_initialized_p) - return; - - c_eh_initialized_p = true; - eh_personality_libfunc - = init_one_libfunc (USING_SJLJ_EXCEPTIONS - ? "__gcc_personality_sj0" - : "__gcc_personality_v0"); - default_init_unwind_resume_libfunc (); - using_eh_for_cleanups (); -} - /* Finish processing of a declaration; install its initial value. If the length of an array type is not known before, @@ -3337,13 +2697,12 @@ c_maybe_initialize_eh (void) void finish_decl (tree decl, tree init, tree asmspec_tree) { - tree type; + tree type = TREE_TYPE (decl); int was_incomplete = (DECL_SIZE (decl) == 0); const char *asmspec = 0; /* If a name was specified, get the string. */ - if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) - && DECL_FILE_SCOPE_P (decl)) + if (current_scope == global_scope) asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree); if (asmspec_tree) asmspec = TREE_STRING_POINTER (asmspec_tree); @@ -3360,86 +2719,56 @@ finish_decl (tree decl, tree init, tree asmspec_tree) store_init_value (decl, init); if (c_dialect_objc () && (TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == FIELD_DECL)) + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == FIELD_DECL)) objc_check_decl (decl); - type = TREE_TYPE (decl); - /* Deduce size of array from initialization, if not already known. */ if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0 && TREE_CODE (decl) != TYPE_DECL) { - bool do_default + int do_default = (TREE_STATIC (decl) /* Even if pedantic, an external linkage array may have incomplete type at first. */ ? pedantic && !TREE_PUBLIC (decl) : !DECL_EXTERNAL (decl)); int failure - = complete_array_type (&TREE_TYPE (decl), DECL_INITIAL (decl), - do_default); + = complete_array_type (type, DECL_INITIAL (decl), do_default); /* Get the completed type made by complete_array_type. */ type = TREE_TYPE (decl); - switch (failure) - { - case 1: - error ("initializer fails to determine size of %q+D", decl); - break; + if (failure == 1) + error ("%Jinitializer fails to determine size of '%D'", decl, decl); - case 2: + else if (failure == 2) + { if (do_default) - error ("array size missing in %q+D", decl); + error ("%Jarray size missing in '%D'", decl, decl); /* If a `static' var's size isn't known, make it extern as well as static, so it does not get allocated. If it is not `static', then do not mark extern; finish_incomplete_decl will give it a default size and it will get allocated. */ - else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl)) + else if (!pedantic && TREE_STATIC (decl) && ! TREE_PUBLIC (decl)) DECL_EXTERNAL (decl) = 1; - break; - - case 3: - error ("zero or negative size array %q+D", decl); - break; - - case 0: - /* For global variables, update the copy of the type that - exists in the binding. */ - if (TREE_PUBLIC (decl)) - { - struct c_binding *b_ext = I_SYMBOL_BINDING (DECL_NAME (decl)); - while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext)) - b_ext = b_ext->shadowed; - if (b_ext) - { - if (b_ext->type) - b_ext->type = composite_type (b_ext->type, type); - else - b_ext->type = type; - } - } - break; - - default: - gcc_unreachable (); } - if (DECL_INITIAL (decl)) - TREE_TYPE (DECL_INITIAL (decl)) = type; + /* TYPE_MAX_VALUE is always one less than the number of elements + in the array, because we start counting at zero. Therefore, + warn only if the value is less than zero. */ + else if (pedantic && TYPE_DOMAIN (type) != 0 + && tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < 0) + error ("%Jzero or negative size array '%D'", decl, decl); layout_decl (decl, 0); } if (TREE_CODE (decl) == VAR_DECL) { - if (init && TREE_CODE (init) == CONSTRUCTOR) - add_flexible_array_elts_to_size (decl, init); - if (DECL_SIZE (decl) == 0 && TREE_TYPE (decl) != error_mark_node && COMPLETE_TYPE_P (TREE_TYPE (decl))) layout_decl (decl, 0); @@ -3448,20 +2777,22 @@ finish_decl (tree decl, tree init, tree asmspec_tree) /* Don't give an error if we already gave one earlier. */ && TREE_TYPE (decl) != error_mark_node && (TREE_STATIC (decl) - /* A static variable with an incomplete type - is an error if it is initialized. - Also if it is not file scope. - Otherwise, let it through, but if it is not `extern' - then it may cause an error message later. */ - ? (DECL_INITIAL (decl) != 0 + ? + /* A static variable with an incomplete type + is an error if it is initialized. + Also if it is not file scope. + Otherwise, let it through, but if it is not `extern' + then it may cause an error message later. */ + (DECL_INITIAL (decl) != 0 || !DECL_FILE_SCOPE_P (decl)) - /* An automatic variable with an incomplete type - is an error. */ - : !DECL_EXTERNAL (decl))) - { - error ("storage size of %q+D isn%'t known", decl); - TREE_TYPE (decl) = error_mark_node; - } + : + /* An automatic variable with an incomplete type + is an error. */ + !DECL_EXTERNAL (decl))) + { + error ("%Jstorage size of '%D' isn't known", decl, decl); + TREE_TYPE (decl) = error_mark_node; + } if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl)) && DECL_SIZE (decl) != 0) @@ -3469,7 +2800,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree) if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) constant_expression_warning (DECL_SIZE (decl)); else - error ("storage size of %q+D isn%'t constant", decl); + error ("%Jstorage size of '%D' isn't constant", decl, decl); } if (TREE_USED (type)) @@ -3481,13 +2812,36 @@ finish_decl (tree decl, tree init, tree asmspec_tree) was a normal built-in. */ if (TREE_CODE (decl) == FUNCTION_DECL && asmspec) { + /* ASMSPEC is given, and not the name of a register. Mark the + name with a star so assemble_name won't munge it. */ + char *starred = alloca (strlen (asmspec) + 2); + starred[0] = '*'; + strcpy (starred + 1, asmspec); + if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL) - set_builtin_user_assembler_name (decl, asmspec); - set_user_assembler_name (decl, asmspec); + { + tree builtin = built_in_decls [DECL_FUNCTION_CODE (decl)]; + SET_DECL_RTL (builtin, NULL_RTX); + SET_DECL_ASSEMBLER_NAME (builtin, get_identifier (starred)); +#ifdef TARGET_MEM_FUNCTIONS + if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMCPY) + init_block_move_fn (starred); + else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMSET) + init_block_clear_fn (starred); +#else + if (DECL_FUNCTION_CODE (decl) == BUILT_IN_BCOPY) + init_block_move_fn (starred); + else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_BZERO) + init_block_clear_fn (starred); +#endif + } + SET_DECL_RTL (decl, NULL_RTX); + change_decl_assembler_name (decl, get_identifier (starred)); } /* If #pragma weak was used, mark the decl weak now. */ - maybe_apply_pragma_weak (decl); + if (current_scope == global_scope) + maybe_apply_pragma_weak (decl); /* Output the assembler code and/or RTL code for variables and functions, unless the type is an undefined structure or union. @@ -3495,31 +2849,10 @@ finish_decl (tree decl, tree init, tree asmspec_tree) if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL) { - /* Determine the ELF visibility. */ - if (TREE_PUBLIC (decl)) - c_determine_visibility (decl); - /* This is a no-op in c-lang.c or something real in objc-act.c. */ if (c_dialect_objc ()) objc_check_decl (decl); - if (asmspec) - { - /* If this is not a static variable, issue a warning. - It doesn't make any sense to give an ASMSPEC for an - ordinary, non-register local variable. Historically, - GCC has accepted -- but ignored -- the ASMSPEC in - this case. */ - if (!DECL_FILE_SCOPE_P (decl) - && TREE_CODE (decl) == VAR_DECL - && !C_DECL_REGISTER (decl) - && !TREE_STATIC (decl)) - warning (0, "ignoring asm-specifier for non-static local " - "variable %q+D", decl); - else - set_user_assembler_name (decl, asmspec); - } - if (DECL_FILE_SCOPE_P (decl)) { if (DECL_INITIAL (decl) == NULL_TREE @@ -3528,51 +2861,44 @@ finish_decl (tree decl, tree init, tree asmspec_tree) when a tentative file-scope definition is seen. But at end of compilation, do output code for them. */ DECL_DEFER_OUTPUT (decl) = 1; - rest_of_decl_compilation (decl, true, 0); + rest_of_decl_compilation (decl, asmspec, true, 0); } else { - /* In conjunction with an ASMSPEC, the `register' - keyword indicates that we should place the variable - in a particular register. */ - if (asmspec && C_DECL_REGISTER (decl)) + /* This is a local variable. If there is an ASMSPEC, the + user has requested that we handle it specially. */ + if (asmspec) { - DECL_HARD_REGISTER (decl) = 1; - /* This cannot be done for a structure with volatile - fields, on which DECL_REGISTER will have been - reset. */ - if (!DECL_REGISTER (decl)) - error ("cannot put object with volatile field into register"); + /* In conjunction with an ASMSPEC, the `register' + keyword indicates that we should place the variable + in a particular register. */ + if (DECL_REGISTER (decl)) + DECL_C_HARD_REGISTER (decl) = 1; + + /* If this is not a static variable, issue a warning. + It doesn't make any sense to give an ASMSPEC for an + ordinary, non-register local variable. Historically, + GCC has accepted -- but ignored -- the ASMSPEC in + this case. */ + if (TREE_CODE (decl) == VAR_DECL + && !DECL_REGISTER (decl) + && !TREE_STATIC (decl)) + warning ("%Jignoring asm-specifier for non-static local " + "variable '%D'", decl, decl); + else + change_decl_assembler_name (decl, get_identifier (asmspec)); } if (TREE_CODE (decl) != FUNCTION_DECL) - { - /* If we're building a variable sized type, and we might be - reachable other than via the top of the current binding - level, then create a new BIND_EXPR so that we deallocate - the object at the right time. */ - /* Note that DECL_SIZE can be null due to errors. */ - if (DECL_SIZE (decl) - && !TREE_CONSTANT (DECL_SIZE (decl)) - && STATEMENT_LIST_HAS_LABEL (cur_stmt_list)) - { - tree bind; - bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); - TREE_SIDE_EFFECTS (bind) = 1; - add_stmt (bind); - BIND_EXPR_BODY (bind) = push_stmt_list (); - } - add_stmt (build_stmt (DECL_EXPR, decl)); - } + add_decl_stmt (decl); } - if (!DECL_FILE_SCOPE_P (decl)) { /* Recompute the RTL of a local array now if it used to be an incomplete type. */ if (was_incomplete - && !TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) + && ! TREE_STATIC (decl) && ! DECL_EXTERNAL (decl)) { /* If we used it already as memory, it must stay in memory. */ TREE_ADDRESSABLE (decl) = TREE_USED (decl); @@ -3584,22 +2910,16 @@ finish_decl (tree decl, tree init, tree asmspec_tree) } /* If this was marked 'used', be sure it will be output. */ - if (!flag_unit_at_a_time && lookup_attribute ("used", DECL_ATTRIBUTES (decl))) - mark_decl_referenced (decl); + if (lookup_attribute ("used", DECL_ATTRIBUTES (decl))) + mark_referenced (DECL_ASSEMBLER_NAME (decl)); if (TREE_CODE (decl) == TYPE_DECL) - { - if (!DECL_FILE_SCOPE_P (decl) - && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) - add_stmt (build_stmt (DECL_EXPR, decl)); - - rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0); - } + rest_of_decl_compilation (decl, NULL, DECL_FILE_SCOPE_P (decl), 0); /* At the end of a declaration, throw away any variable type sizes of types defined inside that declaration. There is no use computing them in the following function definition. */ - if (current_scope == file_scope) + if (current_scope == global_scope) get_pending_sizes (); /* Install a cleanup (aka destructor) if one was given. */ @@ -3608,6 +2928,8 @@ finish_decl (tree decl, tree init, tree asmspec_tree) tree attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl)); if (attr) { + static bool eh_initialized_p; + tree cleanup_id = TREE_VALUE (TREE_VALUE (attr)); tree cleanup_decl = lookup_name (cleanup_id); tree cleanup; @@ -3619,52 +2941,67 @@ finish_decl (tree decl, tree init, tree asmspec_tree) /* Don't warn about decl unused; the cleanup uses it. */ TREE_USED (decl) = 1; - TREE_USED (cleanup_decl) = 1; /* Initialize EH, if we've been told to do so. */ - c_maybe_initialize_eh (); + if (flag_exceptions && !eh_initialized_p) + { + eh_initialized_p = true; + eh_personality_libfunc + = init_one_libfunc (USING_SJLJ_EXCEPTIONS + ? "__gcc_personality_sj0" + : "__gcc_personality_v0"); + using_eh_for_cleanups (); + } - push_cleanup (decl, cleanup, false); + add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup)); } } } -/* Given a parsed parameter declaration, decode it into a PARM_DECL. */ - -tree -grokparm (const struct c_parm *parm) -{ - tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, - NULL); - - decl_attributes (&decl, parm->attrs, 0); - - return decl; -} - /* Given a parsed parameter declaration, decode it into a PARM_DECL and push that on the current scope. */ void -push_parm_decl (const struct c_parm *parm) +push_parm_decl (tree parm) { tree decl; + int old_dont_save_pending_sizes_p = 0; - decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL); - decl_attributes (&decl, parm->attrs, 0); + /* Don't attempt to expand sizes while parsing this decl. + (We can get here with i_s_e 1 somehow from Objective-C.) */ + int save_immediate_size_expand = immediate_size_expand; + immediate_size_expand = 0; + + /* If this is a nested function, we do want to keep SAVE_EXPRs for + the argument sizes, regardless of the parent's setting. */ + if (cfun) + { + old_dont_save_pending_sizes_p = cfun->x_dont_save_pending_sizes_p; + cfun->x_dont_save_pending_sizes_p = 0; + } + + decl = grokdeclarator (TREE_VALUE (TREE_PURPOSE (parm)), + TREE_PURPOSE (TREE_PURPOSE (parm)), + PARM, 0, NULL); + decl_attributes (&decl, TREE_VALUE (parm), 0); decl = pushdecl (decl); finish_decl (decl, NULL_TREE, NULL_TREE); + + if (cfun) + cfun->x_dont_save_pending_sizes_p = old_dont_save_pending_sizes_p; + immediate_size_expand = save_immediate_size_expand; } -/* Mark all the parameter declarations to date as forward decls. +/* Mark all the parameter declarations to date as forward decls, + shift them to the variables list, and reset the parameters list. Also diagnose use of this extension. */ void mark_forward_parm_decls (void) { - struct c_binding *b; + tree parm; if (pedantic && !current_scope->warned_forward_parm_decls) { @@ -3672,11 +3009,16 @@ mark_forward_parm_decls (void) current_scope->warned_forward_parm_decls = true; } - for (b = current_scope->bindings; b; b = b->prev) - if (TREE_CODE (b->decl) == PARM_DECL) - TREE_ASM_WRITTEN (b->decl) = 1; + for (parm = current_scope->parms; parm; parm = TREE_CHAIN (parm)) + TREE_ASM_WRITTEN (parm) = 1; + + SCOPE_LIST_CONCAT (current_scope, names, current_scope, parms); + current_scope->parms = 0; + current_scope->parms_last = 0; } +static GTY(()) int compound_literal_number; + /* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound literal, which may be an incomplete array type completed by the initializer; INIT is a CONSTRUCTOR that initializes the compound @@ -3687,58 +3029,123 @@ build_compound_literal (tree type, tree init) { /* We do not use start_decl here because we have a type, not a declarator; and do not use finish_decl because the decl should be stored inside - the COMPOUND_LITERAL_EXPR rather than added elsewhere as a DECL_EXPR. */ - tree decl; + the COMPOUND_LITERAL_EXPR rather than added elsewhere as a DECL_STMT. */ + tree decl = build_decl (VAR_DECL, NULL_TREE, type); tree complit; tree stmt; - - if (type == error_mark_node) - return error_mark_node; - - decl = build_decl (VAR_DECL, NULL_TREE, type); DECL_EXTERNAL (decl) = 0; TREE_PUBLIC (decl) = 0; - TREE_STATIC (decl) = (current_scope == file_scope); + TREE_STATIC (decl) = (current_scope == global_scope); DECL_CONTEXT (decl) = current_function_decl; TREE_USED (decl) = 1; TREE_TYPE (decl) = type; - TREE_READONLY (decl) = TYPE_READONLY (type); + TREE_READONLY (decl) = TREE_READONLY (type); store_init_value (decl, init); if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type)) { - int failure = complete_array_type (&TREE_TYPE (decl), - DECL_INITIAL (decl), true); - gcc_assert (!failure); - - type = TREE_TYPE (decl); - TREE_TYPE (DECL_INITIAL (decl)) = type; + int failure = complete_array_type (type, DECL_INITIAL (decl), 1); + if (failure) + abort (); } + type = TREE_TYPE (decl); if (type == error_mark_node || !COMPLETE_TYPE_P (type)) return error_mark_node; - stmt = build_stmt (DECL_EXPR, decl); - complit = build1 (COMPOUND_LITERAL_EXPR, type, stmt); + stmt = build_stmt (DECL_STMT, decl); + complit = build1 (COMPOUND_LITERAL_EXPR, TREE_TYPE (decl), stmt); TREE_SIDE_EFFECTS (complit) = 1; layout_decl (decl, 0); if (TREE_STATIC (decl)) { - /* This decl needs a name for the assembler output. */ - set_compound_literal_name (decl); + /* This decl needs a name for the assembler output. We also need + a unique suffix to be added to the name. */ + char *name; + + ASM_FORMAT_PRIVATE_NAME (name, "__compound_literal", + compound_literal_number); + compound_literal_number++; + DECL_NAME (decl) = get_identifier (name); DECL_DEFER_OUTPUT (decl) = 1; DECL_COMDAT (decl) = 1; DECL_ARTIFICIAL (decl) = 1; - DECL_IGNORED_P (decl) = 1; pushdecl (decl); - rest_of_decl_compilation (decl, 1, 0); + rest_of_decl_compilation (decl, NULL, 1, 0); } return complit; } +/* Make TYPE a complete type based on INITIAL_VALUE. + Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered, + 2 if there was no information (in which case assume 1 if DO_DEFAULT). */ + +int +complete_array_type (tree type, tree initial_value, int do_default) +{ + tree maxindex = NULL_TREE; + int value = 0; + + if (initial_value) + { + /* Note MAXINDEX is really the maximum index, + one less than the size. */ + if (TREE_CODE (initial_value) == STRING_CST) + { + int eltsize + = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value))); + maxindex = build_int_2 ((TREE_STRING_LENGTH (initial_value) + / eltsize) - 1, 0); + } + else if (TREE_CODE (initial_value) == CONSTRUCTOR) + { + tree elts = CONSTRUCTOR_ELTS (initial_value); + maxindex = build_int_2 (-1, -1); + for (; elts; elts = TREE_CHAIN (elts)) + { + if (TREE_PURPOSE (elts)) + maxindex = TREE_PURPOSE (elts); + else + maxindex = fold (build (PLUS_EXPR, integer_type_node, + maxindex, integer_one_node)); + } + maxindex = copy_node (maxindex); + } + else + { + /* Make an error message unless that happened already. */ + if (initial_value != error_mark_node) + value = 1; + + /* Prevent further error messages. */ + maxindex = build_int_2 (0, 0); + } + } + + if (!maxindex) + { + if (do_default) + maxindex = build_int_2 (0, 0); + value = 2; + } + + if (maxindex) + { + TYPE_DOMAIN (type) = build_index_type (maxindex); + if (!TREE_TYPE (maxindex)) + TREE_TYPE (maxindex) = TYPE_DOMAIN (type); + } + + /* Lay out the type now that we can get the real answer. */ + + layout_type (type); + + return value; +} + /* Determine whether TYPE is a structure with a flexible array member, or a union containing such a structure (possibly recursively). */ @@ -3782,12 +3189,14 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name) unsigned HOST_WIDE_INT w; const char *name = orig_name ? orig_name: _("<anonymous>"); + /* Necessary? */ + STRIP_NOPS (*width); + /* Detect and ignore out of range field width and process valid field widths. */ - if (!INTEGRAL_TYPE_P (TREE_TYPE (*width)) - || TREE_CODE (*width) != INTEGER_CST) + if (TREE_CODE (*width) != INTEGER_CST) { - error ("bit-field %qs width not an integer constant", name); + error ("bit-field `%s' width not an integer constant", name); *width = integer_one_node; } else @@ -3795,12 +3204,12 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name) constant_expression_warning (*width); if (tree_int_cst_sgn (*width) < 0) { - error ("negative width in bit-field %qs", name); + error ("negative width in bit-field `%s'", name); *width = integer_one_node; } else if (integer_zerop (*width) && orig_name) { - error ("zero width for bit-field %qs", name); + error ("zero width for bit-field `%s'", name); *width = integer_one_node; } } @@ -3810,17 +3219,16 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name) && TREE_CODE (*type) != BOOLEAN_TYPE && TREE_CODE (*type) != ENUMERAL_TYPE) { - error ("bit-field %qs has invalid type", name); + error ("bit-field `%s' has invalid type", name); *type = unsigned_type_node; } type_mv = TYPE_MAIN_VARIANT (*type); if (pedantic - && !in_system_header && type_mv != integer_type_node && type_mv != unsigned_type_node && type_mv != boolean_type_node) - pedwarn ("type of bit-field %qs is a GCC extension", name); + pedwarn ("type of bit-field `%s' is a GCC extension", name); if (type_mv == boolean_type_node) max_width = CHAR_TYPE_SIZE; @@ -3829,23 +3237,18 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name) if (0 < compare_tree_int (*width, max_width)) { - error ("width of %qs exceeds its type", name); + error ("width of `%s' exceeds its type", name); w = max_width; - *width = build_int_cst (NULL_TREE, w); + *width = build_int_2 (w, 0); } else w = tree_low_cst (*width, 1); - if (TREE_CODE (*type) == ENUMERAL_TYPE) - { - struct lang_type *lt = TYPE_LANG_SPECIFIC (*type); - if (!lt - || w < min_precision (lt->enum_min, TYPE_UNSIGNED (*type)) - || w < min_precision (lt->enum_max, TYPE_UNSIGNED (*type))) - warning (0, "%qs is narrower than values of its type", name); - } + if (TREE_CODE (*type) == ENUMERAL_TYPE + && (w < min_precision (TYPE_MIN_VALUE (*type), TREE_UNSIGNED (*type)) + || w < min_precision (TYPE_MAX_VALUE (*type), TREE_UNSIGNED (*type)))) + warning ("`%s' is narrower than values of its type", name); } - /* Given declspecs and a declarator, determine the name and type of the object declared @@ -3853,7 +3256,8 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name) (In one case we can return a ..._TYPE node instead. For invalid input we sometimes return 0.) - DECLSPECS is a c_declspecs structure for the declaration specifiers. + DECLSPECS is a chain of tree_list nodes whose value fields + are the storage classes and type specifiers. DECL_CONTEXT says which syntactic context this declaration is in: NORMAL for most contexts. Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL. @@ -3865,7 +3269,7 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name) TYPENAME if for a typename (in a cast or sizeof). Don't make a DECL node; just return the ..._TYPE node. FIELD for a struct or union field; make a FIELD_DECL. - INITIALIZED is true if the decl has an initializer. + INITIALIZED is 1 if the decl has an initializer. WIDTH is non-NULL for bit-fields, and is a pointer to an INTEGER_CST node representing the width of the bit-field. @@ -3877,63 +3281,64 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name) and `extern' are interpreted. */ static tree -grokdeclarator (const struct c_declarator *declarator, - struct c_declspecs *declspecs, - enum decl_context decl_context, bool initialized, tree *width) +grokdeclarator (tree declarator, tree declspecs, + enum decl_context decl_context, int initialized, tree *width) { - tree type = declspecs->type; - bool threadp = declspecs->thread_p; - enum c_storage_class storage_class = declspecs->storage_class; + int specbits = 0; + tree spec; + tree type = NULL_TREE; + int longlong = 0; int constp; int restrictp; int volatilep; int type_quals = TYPE_UNQUALIFIED; + int inlinep; + int explicit_int = 0; + int explicit_char = 0; + int defaulted_int = 0; + tree typedef_decl = 0; const char *name, *orig_name; tree typedef_type = 0; - bool funcdef_flag = false; - bool funcdef_syntax = false; + int funcdef_flag = 0; + enum tree_code innermost_code = ERROR_MARK; int size_varies = 0; - tree decl_attr = declspecs->decl_attr; - int array_ptr_quals = TYPE_UNQUALIFIED; - tree array_ptr_attrs = NULL_TREE; + tree decl_attr = NULL_TREE; + tree array_ptr_quals = NULL_TREE; int array_parm_static = 0; - bool array_parm_vla_unspec_p = false; tree returned_attrs = NULL_TREE; bool bitfield = width != NULL; tree element_type; - struct c_arg_info *arg_info = 0; if (decl_context == FUNCDEF) - funcdef_flag = true, decl_context = NORMAL; + funcdef_flag = 1, decl_context = NORMAL; /* Look inside a declarator for the name being declared and get it as a string, for an error message. */ { - const struct c_declarator *decl = declarator; + tree decl = declarator; name = 0; while (decl) - switch (decl->kind) + switch (TREE_CODE (decl)) { - case cdk_function: - case cdk_array: - case cdk_pointer: - funcdef_syntax = (decl->kind == cdk_function); - decl = decl->declarator; + case ARRAY_REF: + case INDIRECT_REF: + case CALL_EXPR: + innermost_code = TREE_CODE (decl); + decl = TREE_OPERAND (decl, 0); break; - case cdk_attrs: - decl = decl->declarator; + case TREE_LIST: + decl = TREE_VALUE (decl); break; - case cdk_id: - if (decl->u.id) - name = IDENTIFIER_POINTER (decl->u.id); + case IDENTIFIER_NODE: + name = IDENTIFIER_POINTER (decl); decl = 0; break; default: - gcc_unreachable (); + abort (); } orig_name = name; if (name == 0) @@ -3943,49 +3348,302 @@ grokdeclarator (const struct c_declarator *declarator, /* A function definition's declarator must have the form of a function declarator. */ - if (funcdef_flag && !funcdef_syntax) + if (funcdef_flag && innermost_code != CALL_EXPR) return 0; /* If this looks like a function definition, make it one, even if it occurs where parms are expected. Then store_parm_decls will reject it and not use it as a parm. */ - if (decl_context == NORMAL && !funcdef_flag && current_scope->parm_flag) + if (decl_context == NORMAL && !funcdef_flag + && current_scope->parm_flag) decl_context = PARM; - if (declspecs->deprecated_p && deprecated_state != DEPRECATED_SUPPRESS) - warn_deprecated_use (declspecs->type); + /* Look through the decl specs and record which ones appear. + Some typespecs are defined as built-in typenames. + Others, the ones that are modifiers of other types, + are represented by bits in SPECBITS: set the bits for + the modifiers that appear. Storage class keywords are also in SPECBITS. + + If there is a typedef name or a type, store the type in TYPE. + This includes builtin typedefs such as `int'. - if ((decl_context == NORMAL || decl_context == FIELD) - && current_scope == file_scope - && variably_modified_type_p (type, NULL_TREE)) + Set EXPLICIT_INT or EXPLICIT_CHAR if the type is `int' or `char' + and did not come from a user typedef. + + Set LONGLONG if `long' is mentioned twice. */ + + for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) { - error ("variably modified %qs at file scope", name); - type = integer_type_node; + tree id = TREE_VALUE (spec); + + /* If the entire declaration is itself tagged as deprecated then + suppress reports of deprecated items. */ + if (id && TREE_DEPRECATED (id)) + { + if (deprecated_state != DEPRECATED_SUPPRESS) + warn_deprecated_use (id); + } + + if (id == ridpointers[(int) RID_INT]) + explicit_int = 1; + if (id == ridpointers[(int) RID_CHAR]) + explicit_char = 1; + + if (TREE_CODE (id) == IDENTIFIER_NODE && C_IS_RESERVED_WORD (id)) + { + enum rid i = C_RID_CODE (id); + if ((int) i <= (int) RID_LAST_MODIFIER) + { + if (i == RID_LONG && (specbits & (1 << (int) RID_LONG))) + { + if (longlong) + error ("`long long long' is too long for GCC"); + else + { + if (pedantic && !flag_isoc99 && ! in_system_header + && warn_long_long) + pedwarn ("ISO C90 does not support `long long'"); + longlong = 1; + } + } + else if (specbits & (1 << (int) i)) + { + if (i == RID_CONST || i == RID_VOLATILE || i == RID_RESTRICT) + { + if (pedantic && !flag_isoc99) + pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id)); + } + else + error ("duplicate `%s'", IDENTIFIER_POINTER (id)); + } + + /* Diagnose "__thread extern". Recall that this list + is in the reverse order seen in the text. */ + if (i == RID_THREAD + && (specbits & (1 << (int) RID_EXTERN + | 1 << (int) RID_STATIC))) + { + if (specbits & 1 << (int) RID_EXTERN) + error ("`__thread' before `extern'"); + else + error ("`__thread' before `static'"); + } + + specbits |= 1 << (int) i; + goto found; + } + } + if (type) + error ("two or more data types in declaration of `%s'", name); + /* Actual typedefs come to us as TYPE_DECL nodes. */ + else if (TREE_CODE (id) == TYPE_DECL) + { + if (TREE_TYPE (id) == error_mark_node) + ; /* Allow the type to default to int to avoid cascading errors. */ + else + { + type = TREE_TYPE (id); + decl_attr = DECL_ATTRIBUTES (id); + typedef_decl = id; + } + } + /* Built-in types come as identifiers. */ + else if (TREE_CODE (id) == IDENTIFIER_NODE) + { + tree t = lookup_name (id); + if (TREE_TYPE (t) == error_mark_node) + ; + else if (!t || TREE_CODE (t) != TYPE_DECL) + error ("`%s' fails to be a typedef or built in type", + IDENTIFIER_POINTER (id)); + else + { + type = TREE_TYPE (t); + typedef_decl = t; + } + } + else if (TREE_CODE (id) != ERROR_MARK) + type = id; + + found: + ; } typedef_type = type; - size_varies = C_TYPE_VARIABLE_SIZE (type); + if (type) + size_varies = C_TYPE_VARIABLE_SIZE (type); - /* Diagnose defaulting to "int". */ + /* No type at all: default to `int', and set DEFAULTED_INT + because it was not a user-defined typedef. */ - if (declspecs->default_int_p && !in_system_header) + if (type == 0) { - /* Issue a warning if this is an ISO C 99 program or if - -Wreturn-type and this is a function, or if -Wimplicit; - prefer the former warning since it is more explicit. */ - if ((warn_implicit_int || warn_return_type || flag_isoc99) - && funcdef_flag) - warn_about_return_type = 1; - else if (warn_implicit_int || flag_isoc99) - pedwarn_c99 ("type defaults to %<int%> in declaration of %qs", name); + if ((! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT) + | (1 << (int) RID_SIGNED) + | (1 << (int) RID_UNSIGNED) + | (1 << (int) RID_COMPLEX)))) + /* Don't warn about typedef foo = bar. */ + && ! (specbits & (1 << (int) RID_TYPEDEF) && initialized) + && ! in_system_header) + { + /* Issue a warning if this is an ISO C 99 program or if -Wreturn-type + and this is a function, or if -Wimplicit; prefer the former + warning since it is more explicit. */ + if ((warn_implicit_int || warn_return_type || flag_isoc99) + && funcdef_flag) + warn_about_return_type = 1; + else if (warn_implicit_int || flag_isoc99) + pedwarn_c99 ("type defaults to `int' in declaration of `%s'", + name); + } + + defaulted_int = 1; + type = integer_type_node; } - /* Adjust the type if a bit-field is being declared, - -funsigned-bitfields applied and the type is not explicitly - "signed". */ - if (bitfield && !flag_signed_bitfields && !declspecs->explicit_signed_p - && TREE_CODE (type) == INTEGER_TYPE) - type = c_common_unsigned_type (type); + /* Now process the modifiers that were specified + and check for invalid combinations. */ + + /* Long double is a special combination. */ + + if ((specbits & 1 << (int) RID_LONG) && ! longlong + && TYPE_MAIN_VARIANT (type) == double_type_node) + { + specbits &= ~(1 << (int) RID_LONG); + type = long_double_type_node; + } + + /* Check all other uses of type modifiers. */ + + if (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT) + | (1 << (int) RID_UNSIGNED) | (1 << (int) RID_SIGNED))) + { + int ok = 0; + + if ((specbits & 1 << (int) RID_LONG) + && (specbits & 1 << (int) RID_SHORT)) + error ("both long and short specified for `%s'", name); + else if (((specbits & 1 << (int) RID_LONG) + || (specbits & 1 << (int) RID_SHORT)) + && explicit_char) + error ("long or short specified with char for `%s'", name); + else if (((specbits & 1 << (int) RID_LONG) + || (specbits & 1 << (int) RID_SHORT)) + && TREE_CODE (type) == REAL_TYPE) + { + static int already = 0; + + error ("long or short specified with floating type for `%s'", name); + if (! already && ! pedantic) + { + error ("the only valid combination is `long double'"); + already = 1; + } + } + else if ((specbits & 1 << (int) RID_SIGNED) + && (specbits & 1 << (int) RID_UNSIGNED)) + error ("both signed and unsigned specified for `%s'", name); + else if (TREE_CODE (type) != INTEGER_TYPE) + error ("long, short, signed or unsigned invalid for `%s'", name); + else + { + ok = 1; + if (!explicit_int && !defaulted_int && !explicit_char) + { + error ("long, short, signed or unsigned used invalidly for `%s'", + name); + ok = 0; + } + } + + /* Discard the type modifiers if they are invalid. */ + if (! ok) + { + specbits &= ~((1 << (int) RID_LONG) | (1 << (int) RID_SHORT) + | (1 << (int) RID_UNSIGNED) | (1 << (int) RID_SIGNED)); + longlong = 0; + } + } + + if ((specbits & (1 << (int) RID_COMPLEX)) + && TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE) + { + error ("complex invalid for `%s'", name); + specbits &= ~(1 << (int) RID_COMPLEX); + } + + /* Decide whether an integer type is signed or not. + Optionally treat bit-fields as signed by default. */ + if (specbits & 1 << (int) RID_UNSIGNED + || (bitfield && ! flag_signed_bitfields + && (explicit_int || defaulted_int || explicit_char + /* A typedef for plain `int' without `signed' + can be controlled just like plain `int'. */ + || ! (typedef_decl != 0 + && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) + && TREE_CODE (type) != ENUMERAL_TYPE + && !(specbits & 1 << (int) RID_SIGNED))) + { + if (longlong) + type = long_long_unsigned_type_node; + else if (specbits & 1 << (int) RID_LONG) + type = long_unsigned_type_node; + else if (specbits & 1 << (int) RID_SHORT) + type = short_unsigned_type_node; + else if (type == char_type_node) + type = unsigned_char_type_node; + else if (typedef_decl) + type = c_common_unsigned_type (type); + else + type = unsigned_type_node; + } + else if ((specbits & 1 << (int) RID_SIGNED) + && type == char_type_node) + type = signed_char_type_node; + else if (longlong) + type = long_long_integer_type_node; + else if (specbits & 1 << (int) RID_LONG) + type = long_integer_type_node; + else if (specbits & 1 << (int) RID_SHORT) + type = short_integer_type_node; + + if (specbits & 1 << (int) RID_COMPLEX) + { + if (pedantic && !flag_isoc99) + pedwarn ("ISO C90 does not support complex types"); + /* If we just have "complex", it is equivalent to + "complex double", but if any modifiers at all are specified it is + the complex form of TYPE. E.g, "complex short" is + "complex short int". */ + + if (defaulted_int && ! longlong + && ! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT) + | (1 << (int) RID_SIGNED) + | (1 << (int) RID_UNSIGNED)))) + { + if (pedantic) + pedwarn ("ISO C does not support plain `complex' meaning `double complex'"); + type = complex_double_type_node; + } + else if (type == integer_type_node) + { + if (pedantic) + pedwarn ("ISO C does not support complex integer types"); + type = complex_integer_type_node; + } + else if (type == float_type_node) + type = complex_float_type_node; + else if (type == double_type_node) + type = complex_double_type_node; + else if (type == long_double_type_node) + type = complex_long_double_type_node; + else + { + if (pedantic) + pedwarn ("ISO C does not support complex integer types"); + type = build_complex_type (type); + } + } /* Figure out the type qualifiers for the declaration. There are two ways a declaration can become qualified. One is something @@ -3999,132 +3657,141 @@ grokdeclarator (const struct c_declarator *declarator, duplicate qualifiers should be diagnosed in this case, but it seems most appropriate to do so). */ element_type = strip_array_types (type); - constp = declspecs->const_p + TYPE_READONLY (element_type); - restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type); - volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type); + constp = !! (specbits & 1 << (int) RID_CONST) + TYPE_READONLY (element_type); + restrictp + = !! (specbits & 1 << (int) RID_RESTRICT) + TYPE_RESTRICT (element_type); + volatilep + = !! (specbits & 1 << (int) RID_VOLATILE) + TYPE_VOLATILE (element_type); + inlinep = !! (specbits & (1 << (int) RID_INLINE)); if (pedantic && !flag_isoc99) { if (constp > 1) - pedwarn ("duplicate %<const%>"); + pedwarn ("duplicate `const'"); if (restrictp > 1) - pedwarn ("duplicate %<restrict%>"); + pedwarn ("duplicate `restrict'"); if (volatilep > 1) - pedwarn ("duplicate %<volatile%>"); + pedwarn ("duplicate `volatile'"); } - if (!flag_gen_aux_info && (TYPE_QUALS (element_type))) + if (! flag_gen_aux_info && (TYPE_QUALS (type))) type = TYPE_MAIN_VARIANT (type); type_quals = ((constp ? TYPE_QUAL_CONST : 0) | (restrictp ? TYPE_QUAL_RESTRICT : 0) | (volatilep ? TYPE_QUAL_VOLATILE : 0)); - /* Warn about storage classes that are invalid for certain - kinds of declarations (parameters, typenames, etc.). */ - - if (funcdef_flag - && (threadp - || storage_class == csc_auto - || storage_class == csc_register - || storage_class == csc_typedef)) - { - if (storage_class == csc_auto - && (pedantic || current_scope == file_scope)) - pedwarn ("function definition declared %<auto%>"); - if (storage_class == csc_register) - error ("function definition declared %<register%>"); - if (storage_class == csc_typedef) - error ("function definition declared %<typedef%>"); - if (threadp) - error ("function definition declared %<__thread%>"); - threadp = false; - if (storage_class == csc_auto - || storage_class == csc_register - || storage_class == csc_typedef) - storage_class = csc_none; - } - else if (decl_context != NORMAL && (storage_class != csc_none || threadp)) - { - if (decl_context == PARM && storage_class == csc_register) - ; - else - { - switch (decl_context) - { - case FIELD: - error ("storage class specified for structure field %qs", - name); - break; - case PARM: - error ("storage class specified for parameter %qs", name); - break; - default: - error ("storage class specified for typename"); - break; - } - storage_class = csc_none; - threadp = false; - } - } - else if (storage_class == csc_extern - && initialized - && !funcdef_flag) - { - /* 'extern' with initialization is invalid if not at file scope. */ - if (current_scope == file_scope) - { - /* It is fine to have 'extern const' when compiling at C - and C++ intersection. */ - if (!(warn_cxx_compat && constp)) - warning (0, "%qs initialized and declared %<extern%>", name); - } - else - error ("%qs has both %<extern%> and initializer", name); - } - else if (current_scope == file_scope) - { - if (storage_class == csc_auto) - error ("file-scope declaration of %qs specifies %<auto%>", name); - if (pedantic && storage_class == csc_register) - pedwarn ("file-scope declaration of %qs specifies %<register%>", name); - } - else - { - if (storage_class == csc_extern && funcdef_flag) - error ("nested function %qs declared %<extern%>", name); - else if (threadp && storage_class == csc_none) - { - error ("function-scope %qs implicitly auto and declared " - "%<__thread%>", - name); - threadp = false; - } - } + /* Warn if two storage classes are given. Default to `auto'. */ + + { + int nclasses = 0; + + if (specbits & 1 << (int) RID_AUTO) nclasses++; + if (specbits & 1 << (int) RID_STATIC) nclasses++; + if (specbits & 1 << (int) RID_EXTERN) nclasses++; + if (specbits & 1 << (int) RID_REGISTER) nclasses++; + if (specbits & 1 << (int) RID_TYPEDEF) nclasses++; + + /* "static __thread" and "extern __thread" are allowed. */ + if ((specbits & (1 << (int) RID_THREAD + | 1 << (int) RID_STATIC + | 1 << (int) RID_EXTERN)) == (1 << (int) RID_THREAD)) + nclasses++; + + /* Warn about storage classes that are invalid for certain + kinds of declarations (parameters, typenames, etc.). */ + + if (nclasses > 1) + error ("multiple storage classes in declaration of `%s'", name); + else if (funcdef_flag + && (specbits + & ((1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO) + | (1 << (int) RID_TYPEDEF) + | (1 << (int) RID_THREAD)))) + { + if (specbits & 1 << (int) RID_AUTO + && (pedantic || current_scope == global_scope)) + pedwarn ("function definition declared `auto'"); + if (specbits & 1 << (int) RID_REGISTER) + error ("function definition declared `register'"); + if (specbits & 1 << (int) RID_TYPEDEF) + error ("function definition declared `typedef'"); + if (specbits & 1 << (int) RID_THREAD) + error ("function definition declared `__thread'"); + specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO) | (1 << (int) RID_THREAD)); + } + else if (decl_context != NORMAL && nclasses > 0) + { + if (decl_context == PARM && specbits & 1 << (int) RID_REGISTER) + ; + else + { + switch (decl_context) + { + case FIELD: + error ("storage class specified for structure field `%s'", + name); + break; + case PARM: + error ("storage class specified for parameter `%s'", name); + break; + default: + error ("storage class specified for typename"); + break; + } + specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC) + | (1 << (int) RID_EXTERN) | (1 << (int) RID_THREAD)); + } + } + else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag) + { + /* `extern' with initialization is invalid if not at file scope. */ + if (current_scope == global_scope) + warning ("`%s' initialized and declared `extern'", name); + else + error ("`%s' has both `extern' and initializer", name); + } + else if (current_scope == global_scope) + { + if (specbits & 1 << (int) RID_AUTO) + error ("file-scope declaration of `%s' specifies `auto'", name); + } + else + { + if (specbits & 1 << (int) RID_EXTERN && funcdef_flag) + error ("nested function `%s' declared `extern'", name); + else if ((specbits & (1 << (int) RID_THREAD + | 1 << (int) RID_EXTERN + | 1 << (int) RID_STATIC)) + == (1 << (int) RID_THREAD)) + { + error ("function-scope `%s' implicitly auto and declared `__thread'", + name); + specbits &= ~(1 << (int) RID_THREAD); + } + } + } /* Now figure out the structure of the declarator proper. Descend through it, creating more complex types, until we reach - the declared identifier (or NULL_TREE, in an absolute declarator). - At each stage we maintain an unqualified version of the type - together with any qualifiers that should be applied to it with - c_build_qualified_type; this way, array types including - multidimensional array types are first built up in unqualified - form and then the qualified form is created with - TYPE_MAIN_VARIANT pointing to the unqualified form. */ + the declared identifier (or NULL_TREE, in an absolute declarator). */ - while (declarator && declarator->kind != cdk_id) + while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE) { if (type == error_mark_node) { - declarator = declarator->declarator; + declarator = TREE_OPERAND (declarator, 0); continue; } - /* Each level of DECLARATOR is either a cdk_array (for ...[..]), - a cdk_pointer (for *...), - a cdk_function (for ...(...)), - a cdk_attrs (for nested attributes), - or a cdk_id (for the name being declared - or the place in an absolute declarator + /* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]), + an INDIRECT_REF (for *...), + a CALL_EXPR (for ...(...)), + a TREE_LIST (for nested attributes), + an identifier (for the name being declared) + or a null pointer (for the place in an absolute declarator where the name was omitted). - For the last case, we have just exited the loop. + For the last two cases, we have just exited the loop. At this point, TYPE is the type of elements of an array, or for a function to return, or for a pointer to point to. @@ -4132,410 +3799,360 @@ grokdeclarator (const struct c_declarator *declarator, array or function or pointer, and DECLARATOR has had its outermost layer removed. */ - if (array_ptr_quals != TYPE_UNQUALIFIED - || array_ptr_attrs != NULL_TREE - || array_parm_static) + if (array_ptr_quals != NULL_TREE || array_parm_static) { /* Only the innermost declarator (making a parameter be of array type which is converted to pointer type) may have static or type qualifiers. */ error ("static or type qualifiers in non-parameter array declarator"); - array_ptr_quals = TYPE_UNQUALIFIED; - array_ptr_attrs = NULL_TREE; + array_ptr_quals = NULL_TREE; array_parm_static = 0; } - switch (declarator->kind) + if (TREE_CODE (declarator) == TREE_LIST) { - case cdk_attrs: - { - /* A declarator with embedded attributes. */ - tree attrs = declarator->u.attrs; - const struct c_declarator *inner_decl; - int attr_flags = 0; - declarator = declarator->declarator; - inner_decl = declarator; - while (inner_decl->kind == cdk_attrs) - inner_decl = inner_decl->declarator; - if (inner_decl->kind == cdk_id) - attr_flags |= (int) ATTR_FLAG_DECL_NEXT; - else if (inner_decl->kind == cdk_function) - attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; - else if (inner_decl->kind == cdk_array) - attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; - returned_attrs = decl_attributes (&type, - chainon (returned_attrs, attrs), - attr_flags); - break; - } - case cdk_array: - { - tree itype = NULL_TREE; - tree size = declarator->u.array.dimen; - /* The index is a signed object `sizetype' bits wide. */ - tree index_type = c_common_signed_type (sizetype); + /* We encode a declarator with embedded attributes using + a TREE_LIST. */ + tree attrs = TREE_PURPOSE (declarator); + tree inner_decl; + int attr_flags = 0; + declarator = TREE_VALUE (declarator); + inner_decl = declarator; + while (inner_decl != NULL_TREE + && TREE_CODE (inner_decl) == TREE_LIST) + inner_decl = TREE_VALUE (inner_decl); + if (inner_decl == NULL_TREE + || TREE_CODE (inner_decl) == IDENTIFIER_NODE) + attr_flags |= (int) ATTR_FLAG_DECL_NEXT; + else if (TREE_CODE (inner_decl) == CALL_EXPR) + attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; + else if (TREE_CODE (inner_decl) == ARRAY_REF) + attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; + returned_attrs = decl_attributes (&type, + chainon (returned_attrs, attrs), + attr_flags); + } + else if (TREE_CODE (declarator) == ARRAY_REF) + { + tree itype = NULL_TREE; + tree size = TREE_OPERAND (declarator, 1); + /* The index is a signed object `sizetype' bits wide. */ + tree index_type = c_common_signed_type (sizetype); - array_ptr_quals = declarator->u.array.quals; - array_ptr_attrs = declarator->u.array.attrs; - array_parm_static = declarator->u.array.static_p; - array_parm_vla_unspec_p = declarator->u.array.vla_unspec_p; + array_ptr_quals = TREE_TYPE (declarator); + array_parm_static = TREE_STATIC (declarator); - declarator = declarator->declarator; + declarator = TREE_OPERAND (declarator, 0); - /* Check for some types that there cannot be arrays of. */ + /* Check for some types that there cannot be arrays of. */ - if (VOID_TYPE_P (type)) - { - error ("declaration of %qs as array of voids", name); - type = error_mark_node; - } + if (VOID_TYPE_P (type)) + { + error ("declaration of `%s' as array of voids", name); + type = error_mark_node; + } - if (TREE_CODE (type) == FUNCTION_TYPE) - { - error ("declaration of %qs as array of functions", name); - type = error_mark_node; - } + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("declaration of `%s' as array of functions", name); + type = error_mark_node; + } - if (pedantic && !in_system_header && flexible_array_type_p (type)) - pedwarn ("invalid use of structure with flexible array member"); + if (pedantic && !in_system_header && flexible_array_type_p (type)) + pedwarn ("invalid use of structure with flexible array member"); - if (size == error_mark_node) - type = error_mark_node; + if (size == error_mark_node) + type = error_mark_node; - if (type == error_mark_node) - continue; + if (type == error_mark_node) + continue; - /* If size was specified, set ITYPE to a range-type for - that size. Otherwise, ITYPE remains null. finish_decl - may figure it out from an initial value. */ + /* If size was specified, set ITYPE to a range-type for that size. + Otherwise, ITYPE remains null. finish_decl may figure it out + from an initial value. */ - if (size) - { - /* Strip NON_LVALUE_EXPRs since we aren't using as an - lvalue. */ - STRIP_TYPE_NOPS (size); + if (size) + { + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (size); - if (!INTEGRAL_TYPE_P (TREE_TYPE (size))) - { - error ("size of array %qs has non-integer type", name); - size = integer_one_node; - } + if (! INTEGRAL_TYPE_P (TREE_TYPE (size))) + { + error ("size of array `%s' has non-integer type", name); + size = integer_one_node; + } - if (pedantic && integer_zerop (size)) - pedwarn ("ISO C forbids zero-size array %qs", name); + if (pedantic && integer_zerop (size)) + pedwarn ("ISO C forbids zero-size array `%s'", name); - if (TREE_CODE (size) == INTEGER_CST) - { - constant_expression_warning (size); - if (tree_int_cst_sgn (size) < 0) - { - error ("size of array %qs is negative", name); - size = integer_one_node; - } - } - else if ((decl_context == NORMAL || decl_context == FIELD) - && current_scope == file_scope) - { - error ("variably modified %qs at file scope", name); - size = integer_one_node; - } - else - { - /* Make sure the array size remains visibly - nonconstant even if it is (eg) a const variable - with known value. */ - size_varies = 1; + if (TREE_CODE (size) == INTEGER_CST) + { + constant_expression_warning (size); + if (tree_int_cst_sgn (size) < 0) + { + error ("size of array `%s' is negative", name); + size = integer_one_node; + } + } + else + { + /* Make sure the array size remains visibly nonconstant + even if it is (eg) a const variable with known value. */ + size_varies = 1; - if (!flag_isoc99 && pedantic) - { - if (TREE_CONSTANT (size)) - pedwarn ("ISO C90 forbids array %qs whose size " - "can%'t be evaluated", - name); - else - pedwarn ("ISO C90 forbids variable-size array %qs", - name); - } - } + if (!flag_isoc99 && pedantic) + { + if (TREE_CONSTANT (size)) + pedwarn ("ISO C90 forbids array `%s' whose size can't be evaluated", + name); + else + pedwarn ("ISO C90 forbids variable-size array `%s'", + name); + } + } - if (integer_zerop (size)) - { - /* A zero-length array cannot be represented with - an unsigned index type, which is what we'll - get with build_index_type. Create an - open-ended range instead. */ - itype = build_range_type (sizetype, size, NULL_TREE); - } - else - { - /* Arrange for the SAVE_EXPR on the inside of the - MINUS_EXPR, which allows the -1 to get folded - with the +1 that happens when building TYPE_SIZE. */ - if (size_varies) - size = variable_size (size); - - /* Compute the maximum valid index, that is, size - - 1. Do the calculation in index_type, so that - if it is a variable the computations will be - done in the proper mode. */ - itype = fold_build2 (MINUS_EXPR, index_type, - convert (index_type, size), - convert (index_type, - size_one_node)); - - /* If that overflowed, the array is too big. ??? - While a size of INT_MAX+1 technically shouldn't - cause an overflow (because we subtract 1), the - overflow is recorded during the conversion to - index_type, before the subtraction. Handling - this case seems like an unnecessary - complication. */ - if (TREE_CODE (itype) == INTEGER_CST - && TREE_OVERFLOW (itype)) - { - error ("size of array %qs is too large", name); - type = error_mark_node; - continue; - } + if (integer_zerop (size)) + { + /* A zero-length array cannot be represented with an + unsigned index type, which is what we'll get with + build_index_type. Create an open-ended range instead. */ + itype = build_range_type (sizetype, size, NULL_TREE); + } + else + { + /* Compute the maximum valid index, that is, size - 1. + Do the calculation in index_type, so that if it is + a variable the computations will be done in the + proper mode. */ + itype = fold (build (MINUS_EXPR, index_type, + convert (index_type, size), + convert (index_type, size_one_node))); + + /* If that overflowed, the array is too big. + ??? While a size of INT_MAX+1 technically shouldn't + cause an overflow (because we subtract 1), the overflow + is recorded during the conversion to index_type, before + the subtraction. Handling this case seems like an + unnecessary complication. */ + if (TREE_OVERFLOW (itype)) + { + error ("size of array `%s' is too large", name); + type = error_mark_node; + continue; + } - itype = build_index_type (itype); - } - } - else if (decl_context == FIELD) - { - if (pedantic && !flag_isoc99 && !in_system_header) - pedwarn ("ISO C90 does not support flexible array members"); + if (size_varies) + { + /* We must be able to distinguish the + SAVE_EXPR_CONTEXT for the variably-sized type + so that we can set it correctly in + set_save_expr_context. The convention is + that all SAVE_EXPRs that need to be reset + have NULL_TREE for their SAVE_EXPR_CONTEXT. */ + tree cfd = current_function_decl; + if (decl_context == PARM) + current_function_decl = NULL_TREE; + itype = variable_size (itype); + if (decl_context == PARM) + current_function_decl = cfd; + } + itype = build_index_type (itype); + } + } + else if (decl_context == FIELD) + { + if (pedantic && !flag_isoc99 && !in_system_header) + pedwarn ("ISO C90 does not support flexible array members"); - /* ISO C99 Flexible array members are effectively - identical to GCC's zero-length array extension. */ - itype = build_range_type (sizetype, size_zero_node, NULL_TREE); - } - else if (decl_context == PARM) - { - if (array_parm_vla_unspec_p) - { - if (! orig_name) - { - /* C99 6.7.5.2p4 */ - error ("%<[*]%> not allowed in other than a declaration"); - } + /* ISO C99 Flexible array members are effectively identical + to GCC's zero-length array extension. */ + itype = build_range_type (sizetype, size_zero_node, NULL_TREE); + } - itype = build_range_type (sizetype, size_zero_node, NULL_TREE); - size_varies = 1; - } - } - else if (decl_context == TYPENAME) - { - if (array_parm_vla_unspec_p) - { - /* The error is printed elsewhere. We use this to - avoid messing up with incomplete array types of - the same type, that would otherwise be modified - below. */ - itype = build_range_type (sizetype, size_zero_node, - NULL_TREE); - } - } + /* If pedantic, complain about arrays of incomplete types. */ - /* Complain about arrays of incomplete types. */ - if (!COMPLETE_TYPE_P (type)) - { - error ("array type has incomplete element type"); - type = error_mark_node; - } - else - /* When itype is NULL, a shared incomplete array type is - returned for all array of a given type. Elsewhere we - make sure we don't complete that type before copying - it, but here we want to make sure we don't ever - modify the shared type, so we gcc_assert (itype) - below. */ - type = build_array_type (type, itype); - - if (type != error_mark_node) - { - if (size_varies) - { - /* It is ok to modify type here even if itype is - NULL: if size_varies, we're in a - multi-dimensional array and the inner type has - variable size, so the enclosing shared array type - must too. */ - if (size && TREE_CODE (size) == INTEGER_CST) - type - = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); - C_TYPE_VARIABLE_SIZE (type) = 1; - } + if (pedantic && !COMPLETE_TYPE_P (type)) + pedwarn ("array type has incomplete element type"); - /* The GCC extension for zero-length arrays differs from - ISO flexible array members in that sizeof yields - zero. */ - if (size && integer_zerop (size)) - { - gcc_assert (itype); - TYPE_SIZE (type) = bitsize_zero_node; - TYPE_SIZE_UNIT (type) = size_zero_node; - } - if (array_parm_vla_unspec_p) - { - gcc_assert (itype); - /* The type is complete. C99 6.7.5.2p4 */ - TYPE_SIZE (type) = bitsize_zero_node; - TYPE_SIZE_UNIT (type) = size_zero_node; - } - } + /* Build the array type itself, then merge any constancy or + volatility into the target type. We must do it in this order + to ensure that the TYPE_MAIN_VARIANT field of the array type + is set correctly. */ - if (decl_context != PARM - && (array_ptr_quals != TYPE_UNQUALIFIED - || array_ptr_attrs != NULL_TREE - || array_parm_static)) - { - error ("static or type qualifiers in non-parameter array declarator"); - array_ptr_quals = TYPE_UNQUALIFIED; - array_ptr_attrs = NULL_TREE; - array_parm_static = 0; - } - break; - } - case cdk_function: - { - /* Say it's a definition only for the declarator closest - to the identifier, apart possibly from some - attributes. */ - bool really_funcdef = false; - tree arg_types; - if (funcdef_flag) - { - const struct c_declarator *t = declarator->declarator; - while (t->kind == cdk_attrs) - t = t->declarator; - really_funcdef = (t->kind == cdk_id); - } + type = build_array_type (type, itype); + if (type_quals) + type = c_build_qualified_type (type, type_quals); - /* Declaring a function type. Make sure we have a valid - type for the function to return. */ - if (type == error_mark_node) - continue; + if (size_varies) + C_TYPE_VARIABLE_SIZE (type) = 1; - size_varies = 0; + /* The GCC extension for zero-length arrays differs from + ISO flexible array members in that sizeof yields zero. */ + if (size && integer_zerop (size)) + { + layout_type (type); + TYPE_SIZE (type) = bitsize_zero_node; + TYPE_SIZE_UNIT (type) = size_zero_node; + } + if (decl_context != PARM + && (array_ptr_quals != NULL_TREE || array_parm_static)) + { + error ("static or type qualifiers in non-parameter array declarator"); + array_ptr_quals = NULL_TREE; + array_parm_static = 0; + } + } + else if (TREE_CODE (declarator) == CALL_EXPR) + { + /* Say it's a definition only for the declarator closest to + the identifier, apart possibly from some attributes. */ + bool really_funcdef = false; + tree arg_types; + if (funcdef_flag) + { + tree t = TREE_OPERAND (declarator, 0); + while (TREE_CODE (t) == TREE_LIST) + t = TREE_VALUE (t); + really_funcdef = (TREE_CODE (t) == IDENTIFIER_NODE); + } - /* Warn about some types functions can't return. */ - if (TREE_CODE (type) == FUNCTION_TYPE) - { - error ("%qs declared as function returning a function", name); - type = integer_type_node; - } - if (TREE_CODE (type) == ARRAY_TYPE) - { - error ("%qs declared as function returning an array", name); - type = integer_type_node; - } + /* Declaring a function type. + Make sure we have a valid type for the function to return. */ + if (type == error_mark_node) + continue; - /* Construct the function type and go to the next - inner layer of declarator. */ - arg_info = declarator->u.arg_info; - arg_types = grokparms (arg_info, really_funcdef); - if (really_funcdef) - put_pending_sizes (arg_info->pending_sizes); + size_varies = 0; - /* Type qualifiers before the return type of the function - qualify the return type, not the function type. */ - if (type_quals) - { - /* Type qualifiers on a function return type are - normally permitted by the standard but have no - effect, so give a warning at -Wreturn-type. - Qualifiers on a void return type are banned on - function definitions in ISO C; GCC used to used - them for noreturn functions. */ - if (VOID_TYPE_P (type) && really_funcdef) - pedwarn ("function definition has qualified void return type"); - else - warning (OPT_Wreturn_type, - "type qualifiers ignored on function return type"); + /* Warn about some types functions can't return. */ - type = c_build_qualified_type (type, type_quals); - } - type_quals = TYPE_UNQUALIFIED; + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("`%s' declared as function returning a function", name); + type = integer_type_node; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + error ("`%s' declared as function returning an array", name); + type = integer_type_node; + } - type = build_function_type (type, arg_types); - declarator = declarator->declarator; + /* Construct the function type and go to the next + inner layer of declarator. */ - /* Set the TYPE_CONTEXTs for each tagged type which is local to - the formal parameter list of this FUNCTION_TYPE to point to - the FUNCTION_TYPE node itself. */ + arg_types = grokparms (TREE_OPERAND (declarator, 1), + really_funcdef); + /* Type qualifiers before the return type of the function + qualify the return type, not the function type. */ + if (type_quals) { - tree link; + /* Type qualifiers on a function return type are normally + permitted by the standard but have no effect, so give a + warning at -Wextra. Qualifiers on a void return type have + meaning as a GNU extension, and are banned on function + definitions in ISO C. FIXME: strictly we shouldn't + pedwarn for qualified void return types except on function + definitions, but not doing so could lead to the undesirable + state of a "volatile void" function return type not being + warned about, and a use of the function being compiled + with GNU semantics, with no diagnostics under -pedantic. */ + if (VOID_TYPE_P (type) && pedantic && !in_system_header) + pedwarn ("ISO C forbids qualified void function return type"); + else if (extra_warnings + && !(VOID_TYPE_P (type) + && type_quals == TYPE_QUAL_VOLATILE)) + warning ("type qualifiers ignored on function return type"); - for (link = arg_info->tags; - link; - link = TREE_CHAIN (link)) - TYPE_CONTEXT (TREE_VALUE (link)) = type; + type = c_build_qualified_type (type, type_quals); } - break; - } - case cdk_pointer: + type_quals = TYPE_UNQUALIFIED; + + type = build_function_type (type, arg_types); + declarator = TREE_OPERAND (declarator, 0); + + /* Set the TYPE_CONTEXTs for each tagged type which is local to + the formal parameter list of this FUNCTION_TYPE to point to + the FUNCTION_TYPE node itself. */ + { - /* Merge any constancy or volatility into the target type - for the pointer. */ + tree link; - if (pedantic && TREE_CODE (type) == FUNCTION_TYPE - && type_quals) - pedwarn ("ISO C forbids qualified function types"); - if (type_quals) - type = c_build_qualified_type (type, type_quals); - size_varies = 0; + for (link = last_function_parm_tags; + link; + link = TREE_CHAIN (link)) + TYPE_CONTEXT (TREE_VALUE (link)) = type; + } + } + else if (TREE_CODE (declarator) == INDIRECT_REF) + { + /* Merge any constancy or volatility into the target type + for the pointer. */ - /* When the pointed-to type involves components of variable size, - care must be taken to ensure that the size evaluation code is - emitted early enough to dominate all the possible later uses - and late enough for the variables on which it depends to have - been assigned. - - This is expected to happen automatically when the pointed-to - type has a name/declaration of it's own, but special attention - is required if the type is anonymous. - - We handle the NORMAL and FIELD contexts here by attaching an - artificial TYPE_DECL to such pointed-to type. This forces the - sizes evaluation at a safe point and ensures it is not deferred - until e.g. within a deeper conditional context. - - We expect nothing to be needed here for PARM or TYPENAME. - Pushing a TYPE_DECL at this point for TYPENAME would actually - be incorrect, as we might be in the middle of an expression - with side effects on the pointed-to type size "arguments" prior - to the pointer declaration point and the fake TYPE_DECL in the - enclosing context would force the size evaluation prior to the - side effects. */ - - if (!TYPE_NAME (type) - && (decl_context == NORMAL || decl_context == FIELD) - && variably_modified_type_p (type, NULL_TREE)) - { - tree decl = build_decl (TYPE_DECL, NULL_TREE, type); - DECL_ARTIFICIAL (decl) = 1; - pushdecl (decl); - finish_decl (decl, NULL_TREE, NULL_TREE); - TYPE_NAME (type) = decl; - } + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn ("ISO C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + type_quals = TYPE_UNQUALIFIED; + size_varies = 0; - type = build_pointer_type (type); + type = build_pointer_type (type); - /* Process type qualifiers (such as const or volatile) - that were given inside the `*'. */ - type_quals = declarator->u.pointer_quals; + /* Process a list of type modifier keywords + (such as const or volatile) that were given inside the `*'. */ - declarator = declarator->declarator; - break; - } - default: - gcc_unreachable (); + if (TREE_TYPE (declarator)) + { + tree typemodlist; + int erred = 0; + + constp = 0; + volatilep = 0; + restrictp = 0; + for (typemodlist = TREE_TYPE (declarator); typemodlist; + typemodlist = TREE_CHAIN (typemodlist)) + { + tree qualifier = TREE_VALUE (typemodlist); + + if (C_IS_RESERVED_WORD (qualifier)) + { + if (C_RID_CODE (qualifier) == RID_CONST) + constp++; + else if (C_RID_CODE (qualifier) == RID_VOLATILE) + volatilep++; + else if (C_RID_CODE (qualifier) == RID_RESTRICT) + restrictp++; + else + erred++; + } + else + erred++; + } + + if (erred) + error ("invalid type modifier within pointer declarator"); + if (pedantic && !flag_isoc99) + { + if (constp > 1) + pedwarn ("duplicate `const'"); + if (volatilep > 1) + pedwarn ("duplicate `volatile'"); + if (restrictp > 1) + pedwarn ("duplicate `restrict'"); + } + + type_quals = ((constp ? TYPE_QUAL_CONST : 0) + | (restrictp ? TYPE_QUAL_RESTRICT : 0) + | (volatilep ? TYPE_QUAL_VOLATILE : 0)); + } + + declarator = TREE_OPERAND (declarator, 0); } + else + abort (); + } - /* Now TYPE has the actual type, apart from any qualifiers in - TYPE_QUALS. */ + /* Now TYPE has the actual type. */ /* Check the type and width of a bit-field. */ if (bitfield) @@ -4545,10 +4162,9 @@ grokdeclarator (const struct c_declarator *declarator, if (TREE_CODE (type) == ARRAY_TYPE && COMPLETE_TYPE_P (type) - && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST - && TREE_OVERFLOW (TYPE_SIZE_UNIT (type))) + && TREE_OVERFLOW (TYPE_SIZE (type))) { - error ("size of array %qs is too large", name); + error ("size of array `%s' is too large", name); /* If we proceed with the array type as it is, we'll eventually crash in tree_low_cst(). */ type = error_mark_node; @@ -4556,32 +4172,46 @@ grokdeclarator (const struct c_declarator *declarator, /* If this is declaring a typedef name, return a TYPE_DECL. */ - if (storage_class == csc_typedef) + if (specbits & (1 << (int) RID_TYPEDEF)) { tree decl; + /* Note that the grammar rejects storage classes + in typenames, fields or parameters */ if (pedantic && TREE_CODE (type) == FUNCTION_TYPE && type_quals) pedwarn ("ISO C forbids qualified function types"); if (type_quals) type = c_build_qualified_type (type, type_quals); - decl = build_decl (TYPE_DECL, declarator->u.id, type); - if (declspecs->explicit_signed_p) + decl = build_decl (TYPE_DECL, declarator, type); + if ((specbits & (1 << (int) RID_SIGNED)) + || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; decl_attributes (&decl, returned_attrs, 0); - if (declspecs->inline_p) - pedwarn ("typedef %q+D declared %<inline%>", decl); return decl; } + /* Detect the case of an array type of unspecified size + which came, as such, direct from a typedef name. + We must copy the type, so that each identifier gets + a distinct type, so that each identifier's size can be + controlled separately by its own initializer. */ + + if (type != 0 && typedef_type != 0 + && TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0 + && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type)) + { + type = build_array_type (TREE_TYPE (type), 0); + if (size_varies) + C_TYPE_VARIABLE_SIZE (type) = 1; + } + /* If this is a type name (such as, in a cast or sizeof), compute the type and return it now. */ if (decl_context == TYPENAME) { - /* Note that the grammar rejects storage classes in typenames - and fields. */ - gcc_assert (storage_class == csc_none && !threadp - && !declspecs->inline_p); + /* Note that the grammar rejects storage classes + in typenames, fields or parameters */ if (pedantic && TREE_CODE (type) == FUNCTION_TYPE && type_quals) pedwarn ("ISO C forbids const or volatile function types"); @@ -4591,13 +4221,6 @@ grokdeclarator (const struct c_declarator *declarator, return type; } - if (pedantic && decl_context == FIELD - && variably_modified_type_p (type, NULL_TREE)) - { - /* C99 6.7.2.1p8 */ - pedwarn ("a member of a structure or union cannot have a variably modified type"); - } - /* Aside from typedefs and type names (handle above), `void' at top level (not within pointer) is allowed only in public variables. @@ -4605,13 +4228,13 @@ grokdeclarator (const struct c_declarator *declarator, a better error message can be made later. */ if (VOID_TYPE_P (type) && decl_context != PARM - && !((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE) - && (storage_class == csc_extern - || (current_scope == file_scope - && !(storage_class == csc_static - || storage_class == csc_register))))) + && ! ((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE) + && ((specbits & (1 << (int) RID_EXTERN)) + || (current_scope == global_scope + && !(specbits + & ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER))))))) { - error ("variable or field %qs declared void", name); + error ("variable or field `%s' declared void", name); type = integer_type_node; } @@ -4636,13 +4259,45 @@ grokdeclarator (const struct c_declarator *declarator, if (type_quals) type = c_build_qualified_type (type, type_quals); type = build_pointer_type (type); - type_quals = array_ptr_quals; + type_quals = TYPE_UNQUALIFIED; + if (array_ptr_quals) + { + tree new_ptr_quals, new_ptr_attrs; + int erred = 0; + split_specs_attrs (array_ptr_quals, &new_ptr_quals, &new_ptr_attrs); + /* We don't yet implement attributes in this context. */ + if (new_ptr_attrs != NULL_TREE) + warning ("attributes in parameter array declarator ignored"); + + constp = 0; + volatilep = 0; + restrictp = 0; + for (; new_ptr_quals; new_ptr_quals = TREE_CHAIN (new_ptr_quals)) + { + tree qualifier = TREE_VALUE (new_ptr_quals); - /* We don't yet implement attributes in this context. */ - if (array_ptr_attrs != NULL_TREE) - warning (OPT_Wattributes, - "attributes in parameter array declarator ignored"); + if (C_IS_RESERVED_WORD (qualifier)) + { + if (C_RID_CODE (qualifier) == RID_CONST) + constp++; + else if (C_RID_CODE (qualifier) == RID_VOLATILE) + volatilep++; + else if (C_RID_CODE (qualifier) == RID_RESTRICT) + restrictp++; + else + erred++; + } + else + erred++; + } + + if (erred) + error ("invalid type modifier within array declarator"); + type_quals = ((constp ? TYPE_QUAL_CONST : 0) + | (restrictp ? TYPE_QUAL_RESTRICT : 0) + | (volatilep ? TYPE_QUAL_VOLATILE : 0)); + } size_varies = 0; } else if (TREE_CODE (type) == FUNCTION_TYPE) @@ -4659,7 +4314,7 @@ grokdeclarator (const struct c_declarator *declarator, type_as_written = type; - decl = build_decl (PARM_DECL, declarator->u.id, type); + decl = build_decl (PARM_DECL, declarator, type); if (size_varies) C_DECL_VARIABLE_SIZE (decl) = 1; @@ -4674,31 +4329,29 @@ grokdeclarator (const struct c_declarator *declarator, promoted_type = c_type_promotes_to (type); DECL_ARG_TYPE (decl) = promoted_type; - if (declspecs->inline_p) - pedwarn ("parameter %q+D declared %<inline%>", decl); + DECL_ARG_TYPE_AS_WRITTEN (decl) = type_as_written; } else if (decl_context == FIELD) { - /* Note that the grammar rejects storage classes in typenames - and fields. */ - gcc_assert (storage_class == csc_none && !threadp - && !declspecs->inline_p); - /* Structure field. It may not be a function. */ if (TREE_CODE (type) == FUNCTION_TYPE) { - error ("field %qs declared as a function", name); + error ("field `%s' declared as a function", name); type = build_pointer_type (type); } else if (TREE_CODE (type) != ERROR_MARK - && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type)) + && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type)) { - error ("field %qs has incomplete type", name); + error ("field `%s' has incomplete type", name); type = error_mark_node; } - type = c_build_qualified_type (type, type_quals); - decl = build_decl (FIELD_DECL, declarator->u.id, type); + /* Move type qualifiers down to element of an array. */ + if (TREE_CODE (type) == ARRAY_TYPE && type_quals) + type = build_array_type (c_build_qualified_type (TREE_TYPE (type), + type_quals), + TYPE_DOMAIN (type)); + decl = build_decl (FIELD_DECL, declarator, type); DECL_NONADDRESSABLE_P (decl) = bitfield; if (size_varies) @@ -4706,75 +4359,60 @@ grokdeclarator (const struct c_declarator *declarator, } else if (TREE_CODE (type) == FUNCTION_TYPE) { - if (storage_class == csc_register || threadp) - { - error ("invalid storage class for function %qs", name); - } - else if (current_scope != file_scope) - { - /* Function declaration not at file scope. Storage - classes other than `extern' are not allowed, C99 - 6.7.1p5, and `extern' makes no difference. However, - GCC allows 'auto', perhaps with 'inline', to support - nested functions. */ - if (storage_class == csc_auto) - { - if (pedantic) - pedwarn ("invalid storage class for function %qs", name); - } - else if (storage_class == csc_static) - { - error ("invalid storage class for function %qs", name); - if (funcdef_flag) - storage_class = declspecs->storage_class = csc_none; - else - return 0; - } - } - - decl = build_decl (FUNCTION_DECL, declarator->u.id, type); + /* Every function declaration is "external" + except for those which are inside a function body + in which `auto' is used. + That is a case not specified by ANSI C, + and we use it for forward declarations for nested functions. */ + int extern_ref = (!(specbits & (1 << (int) RID_AUTO)) + || current_scope == global_scope); + + if (specbits & (1 << (int) RID_AUTO) + && (pedantic || current_scope == global_scope)) + pedwarn ("invalid storage class for function `%s'", name); + if (specbits & (1 << (int) RID_REGISTER)) + error ("invalid storage class for function `%s'", name); + if (specbits & (1 << (int) RID_THREAD)) + error ("invalid storage class for function `%s'", name); + /* Function declaration not at file scope. + Storage classes other than `extern' are not allowed + and `extern' makes no difference. */ + if (current_scope != global_scope + && (specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_INLINE))) + && pedantic) + pedwarn ("invalid storage class for function `%s'", name); + + decl = build_decl (FUNCTION_DECL, declarator, type); decl = build_decl_attribute_variant (decl, decl_attr); - DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl); + DECL_LANG_SPECIFIC (decl) + = ggc_alloc_cleared (sizeof (struct lang_decl)); - if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl)) + if (pedantic && type_quals && ! DECL_IN_SYSTEM_HEADER (decl)) pedwarn ("ISO C forbids qualified function types"); - /* GNU C interprets a volatile-qualified function type to indicate + /* GNU C interprets a `volatile void' return type to indicate that the function does not return. */ if ((type_quals & TYPE_QUAL_VOLATILE) && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl)))) - warning (0, "%<noreturn%> function returns non-void value"); - - /* Every function declaration is an external reference - (DECL_EXTERNAL) except for those which are not at file - scope and are explicitly declared "auto". This is - forbidden by standard C (C99 6.7.1p5) and is interpreted by - GCC to signify a forward declaration of a nested function. */ - if (storage_class == csc_auto && current_scope != file_scope) - DECL_EXTERNAL (decl) = 0; - else - DECL_EXTERNAL (decl) = 1; + warning ("`noreturn' function returns non-void value"); + if (extern_ref) + DECL_EXTERNAL (decl) = 1; /* Record absence of global scope for `static' or `auto'. */ TREE_PUBLIC (decl) - = !(storage_class == csc_static || storage_class == csc_auto); - - /* For a function definition, record the argument information - block where store_parm_decls will look for it. */ - if (funcdef_flag) - current_function_arg_info = arg_info; + = !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_AUTO))); - if (declspecs->default_int_p) + if (defaulted_int) C_FUNCTION_IMPLICIT_INT (decl) = 1; /* Record presence of `inline', if it is reasonable. */ - if (flag_hosted && MAIN_NAME_P (declarator->u.id)) + if (MAIN_NAME_P (declarator)) { - if (declspecs->inline_p) - pedwarn ("cannot inline function %<main%>"); + if (inlinep) + warning ("cannot inline function `main'"); } - else if (declspecs->inline_p) + else if (inlinep) { /* Record that the function is declared `inline'. */ DECL_DECLARED_INLINE_P (decl) = 1; @@ -4786,7 +4424,7 @@ grokdeclarator (const struct c_declarator *declarator, if (initialized) { DECL_INLINE (decl) = 1; - if (storage_class == csc_extern) + if (specbits & (1 << (int) RID_EXTERN)) current_extern_inline = 1; } } @@ -4800,62 +4438,66 @@ grokdeclarator (const struct c_declarator *declarator, { /* It's a variable. */ /* An uninitialized decl with `extern' is a reference. */ - int extern_ref = !initialized && storage_class == csc_extern; + int extern_ref = !initialized && (specbits & (1 << (int) RID_EXTERN)); - type = c_build_qualified_type (type, type_quals); + /* Move type qualifiers down to element of an array. */ + if (TREE_CODE (type) == ARRAY_TYPE && type_quals) + { + int saved_align = TYPE_ALIGN(type); + type = build_array_type (c_build_qualified_type (TREE_TYPE (type), + type_quals), + TYPE_DOMAIN (type)); + TYPE_ALIGN (type) = saved_align; + } + else if (type_quals) + type = c_build_qualified_type (type, type_quals); - /* C99 6.2.2p7: It is invalid (compile-time undefined - behavior) to create an 'extern' declaration for a + /* It is invalid to create an `extern' declaration for a variable if there is a global declaration that is - 'static' and the global declaration is not visible. - (If the static declaration _is_ currently visible, - the 'extern' declaration is taken to refer to that decl.) */ - if (extern_ref && current_scope != file_scope) + `static' and the global declaration is not visible. */ + if (extern_ref && current_scope != global_scope) { - tree global_decl = identifier_global_value (declarator->u.id); - tree visible_decl = lookup_name (declarator->u.id); + tree global_decl; + global_decl = identifier_global_value (declarator); if (global_decl - && global_decl != visible_decl && TREE_CODE (global_decl) == VAR_DECL + && lookup_name (declarator) != global_decl && !TREE_PUBLIC (global_decl)) - error ("variable previously declared %<static%> redeclared " - "%<extern%>"); + error ("variable previously declared `static' redeclared " + "`extern'"); } - decl = build_decl (VAR_DECL, declarator->u.id, type); - DECL_SOURCE_LOCATION (decl) = declarator->id_loc; + decl = build_decl (VAR_DECL, declarator, type); if (size_varies) C_DECL_VARIABLE_SIZE (decl) = 1; - if (declspecs->inline_p) - pedwarn ("variable %q+D declared %<inline%>", decl); + if (inlinep) + pedwarn ("%Jvariable '%D' declared `inline'", decl, decl); - /* At file scope, an initialized extern declaration may follow - a static declaration. In that case, DECL_EXTERNAL will be - reset later in start_decl. */ - DECL_EXTERNAL (decl) = (storage_class == csc_extern); + DECL_EXTERNAL (decl) = extern_ref; /* At file scope, the presence of a `static' or `register' storage class specifier, or the absence of all storage class specifiers makes this declaration a definition (perhaps tentative). Also, - the absence of `static' makes it public. */ - if (current_scope == file_scope) + the absence of both `static' and `register' makes it public. */ + if (current_scope == global_scope) { - TREE_PUBLIC (decl) = storage_class != csc_static; + TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC) + | (1 << (int) RID_REGISTER))); TREE_STATIC (decl) = !extern_ref; } /* Not at file scope, only `static' makes a static definition. */ else { - TREE_STATIC (decl) = (storage_class == csc_static); + TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0; TREE_PUBLIC (decl) = extern_ref; } - if (threadp) + if (specbits & 1 << (int) RID_THREAD) { if (targetm.have_tls) - DECL_TLS_MODEL (decl) = decl_default_tls_model (decl); + DECL_THREAD_LOCAL (decl) = 1; else /* A mere warning is sure to result in improper semantics at runtime. Don't bother to allow this to compile. */ @@ -4863,46 +4505,27 @@ grokdeclarator (const struct c_declarator *declarator, } } - if (storage_class == csc_extern - && variably_modified_type_p (type, NULL_TREE)) - { - /* C99 6.7.5.2p2 */ - error ("object with variably modified type must have no linkage"); - } - /* Record `register' declaration for warnings on & and in case doing stupid register allocation. */ - if (storage_class == csc_register) - { - C_DECL_REGISTER (decl) = 1; - DECL_REGISTER (decl) = 1; - } + if (specbits & (1 << (int) RID_REGISTER)) + DECL_REGISTER (decl) = 1; /* Record constancy and volatility. */ c_apply_type_quals_to_decl (type_quals, decl); /* If a type has volatile components, it should be stored in memory. Otherwise, the fact that those components are volatile - will be ignored, and would even crash the compiler. - Of course, this only makes sense on VAR,PARM, and RESULT decl's. */ - if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl)) - && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == RESULT_DECL)) - { - /* It is not an error for a structure with volatile fields to - be declared register, but reset DECL_REGISTER since it - cannot actually go in a register. */ - int was_reg = C_DECL_REGISTER (decl); - C_DECL_REGISTER (decl) = 0; - DECL_REGISTER (decl) = 0; - c_mark_addressable (decl); - C_DECL_REGISTER (decl) = was_reg; - } + will be ignored, and would even crash the compiler. */ + if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl))) + c_mark_addressable (decl); +#ifdef ENABLE_CHECKING /* This is the earliest point at which we might know the assembler name of a variable. Thus, if it's known before this, die horribly. */ - gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl)); + if (DECL_ASSEMBLER_NAME_SET_P (decl)) + abort (); +#endif decl_attributes (&decl, returned_attrs, 0); @@ -4911,295 +4534,218 @@ grokdeclarator (const struct c_declarator *declarator, } /* Decode the parameter-list info for a function type or function definition. - The argument is the value returned by `get_parm_info' (or made in c-parse.c + The argument is the value returned by `get_parm_info' (or made in parse.y if there is an identifier list instead of a parameter decl list). These two functions are separate because when a function returns or receives functions then each is called multiple times but the order of calls is different. The last call to `grokparms' is always the one that contains the formal parameter names of a function definition. + Store in `last_function_parms' a chain of the decls of parms. + Also store in `last_function_parm_tags' a chain of the struct, union, + and enum tags declared among the parms. + Return a list of arg types to use in the FUNCTION_TYPE for this function. - FUNCDEF_FLAG is true for a function definition, false for + FUNCDEF_FLAG is nonzero for a function definition, 0 for a mere declaration. A nonempty identifier-list gets an error message - when FUNCDEF_FLAG is false. */ + when FUNCDEF_FLAG is zero. */ static tree -grokparms (struct c_arg_info *arg_info, bool funcdef_flag) +grokparms (tree parms_info, int funcdef_flag) { - tree arg_types = arg_info->types; - - if (funcdef_flag && arg_info->had_vla_unspec) - { - /* A function definition isn't function prototype scope C99 6.2.1p4. */ - /* C99 6.7.5.2p4 */ - error ("%<[*]%> not allowed in other than function prototype scope"); - } + tree first_parm = TREE_CHAIN (parms_info); - if (arg_types == 0 && !funcdef_flag && !in_system_header) - warning (OPT_Wstrict_prototypes, - "function declaration isn%'t a prototype"); + last_function_parms = TREE_PURPOSE (parms_info); + last_function_parm_tags = TREE_VALUE (parms_info); + last_function_parm_others = TREE_TYPE (parms_info); - if (arg_types == error_mark_node) - return 0; /* don't set TYPE_ARG_TYPES in this case */ + if (warn_strict_prototypes && first_parm == 0 && !funcdef_flag + && !in_system_header) + warning ("function declaration isn't a prototype"); - else if (arg_types && TREE_CODE (TREE_VALUE (arg_types)) == IDENTIFIER_NODE) + if (first_parm != 0 + && TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE) { - if (!funcdef_flag) + if (! funcdef_flag) pedwarn ("parameter names (without types) in function declaration"); - arg_info->parms = arg_info->types; - arg_info->types = 0; + last_function_parms = first_parm; return 0; } else { - tree parm, type, typelt; - unsigned int parmno; - - /* If there is a parameter of incomplete type in a definition, - this is an error. In a declaration this is valid, and a - struct or union type may be completed later, before any calls - or definition of the function. In the case where the tag was - first declared within the parameter list, a warning has - already been given. If a parameter has void type, then - however the function cannot be defined or called, so - warn. */ + tree parm; + tree typelt; + /* If the arg types are incomplete in a declaration, + they must include undefined tags. + These tags can never be defined in the scope of the declaration, + so the types can never be completed, + and no call can be compiled successfully. */ - for (parm = arg_info->parms, typelt = arg_types, parmno = 1; + for (parm = last_function_parms, typelt = first_parm; parm; - parm = TREE_CHAIN (parm), typelt = TREE_CHAIN (typelt), parmno++) - { - type = TREE_VALUE (typelt); - if (type == error_mark_node) - continue; - - if (!COMPLETE_TYPE_P (type)) - { - if (funcdef_flag) - { - if (DECL_NAME (parm)) - error ("parameter %u (%q+D) has incomplete type", - parmno, parm); - else - error ("%Jparameter %u has incomplete type", - parm, parmno); - - TREE_VALUE (typelt) = error_mark_node; - TREE_TYPE (parm) = error_mark_node; - } - else if (VOID_TYPE_P (type)) - { - if (DECL_NAME (parm)) - warning (0, "parameter %u (%q+D) has void type", - parmno, parm); - else - warning (0, "%Jparameter %u has void type", - parm, parmno); - } - } + parm = TREE_CHAIN (parm)) + /* Skip over any enumeration constants declared here. */ + if (TREE_CODE (parm) == PARM_DECL) + { + /* Barf if the parameter itself has an incomplete type. */ + tree type = TREE_VALUE (typelt); + if (type == error_mark_node) + continue; + if (!COMPLETE_TYPE_P (type)) + { + if (funcdef_flag && DECL_NAME (parm) != 0) + error ("parameter `%s' has incomplete type", + IDENTIFIER_POINTER (DECL_NAME (parm))); + else + warning ("parameter has incomplete type"); + if (funcdef_flag) + { + TREE_VALUE (typelt) = error_mark_node; + TREE_TYPE (parm) = error_mark_node; + } + } + typelt = TREE_CHAIN (typelt); + } - if (DECL_NAME (parm) && TREE_USED (parm)) - warn_if_shadowing (parm); - } - return arg_types; + return first_parm; } } -/* Take apart the current scope and return a c_arg_info structure with - info on a parameter list just parsed. - - This structure is later fed to 'grokparms' and 'store_parm_decls'. +/* Return a tree_list node with info on a parameter list just parsed. + The TREE_PURPOSE is a list of decls of those parms. + The TREE_VALUE is a list of structure, union and enum tags defined. + The TREE_CHAIN is a list of argument types to go in the FUNCTION_TYPE. + The TREE_TYPE is a list of non-parameter decls which appeared with the + parameters. + This tree_list node is later fed to `grokparms'. - ELLIPSIS being true means the argument list ended in '...' so don't - append a sentinel (void_list_node) to the end of the type-list. */ + VOID_AT_END nonzero means append `void' to the end of the type-list. + Zero means the parmlist ended with an ellipsis so don't append `void'. */ -struct c_arg_info * -get_parm_info (bool ellipsis) +tree +get_parm_info (int void_at_end) { - struct c_binding *b = current_scope->bindings; - struct c_arg_info *arg_info = XOBNEW (&parser_obstack, - struct c_arg_info); - tree parms = 0; - tree tags = 0; - tree types = 0; - tree others = 0; - + tree decl, type, list; + tree types = 0; + tree *last_type = &types; + tree tags = current_scope->tags; + tree parms = current_scope->parms; + tree others = current_scope->names; static bool explained_incomplete_types = false; bool gave_void_only_once_err = false; - arg_info->parms = 0; - arg_info->tags = 0; - arg_info->types = 0; - arg_info->others = 0; - arg_info->pending_sizes = 0; - arg_info->had_vla_unspec = current_scope->had_vla_unspec; - - /* The bindings in this scope must not get put into a block. - We will take care of deleting the binding nodes. */ - current_scope->bindings = 0; - - /* This function is only called if there was *something* on the - parameter list. */ - gcc_assert (b); - - /* A parameter list consisting solely of 'void' indicates that the - function takes no arguments. But if the 'void' is qualified - (by 'const' or 'volatile'), or has a storage class specifier - ('register'), then the behavior is undefined; issue an error. - Typedefs for 'void' are OK (see DR#157). */ - if (b->prev == 0 /* one binding */ - && TREE_CODE (b->decl) == PARM_DECL /* which is a parameter */ - && !DECL_NAME (b->decl) /* anonymous */ - && VOID_TYPE_P (TREE_TYPE (b->decl))) /* of void type */ + /* Just "void" (and no ellipsis) is special. There are really no parms. + But if the "void" is qualified (by "const" or "volatile"), or has a + storage class specifier ("register"), then the behavior is undefined; + issue an error. Typedefs for "void" are OK (see DR#157). */ + if (void_at_end && parms != 0 + && TREE_CHAIN (parms) == 0 + && VOID_TYPE_P (TREE_TYPE (parms)) + && !DECL_NAME (parms)) { - if (TREE_THIS_VOLATILE (b->decl) - || TREE_READONLY (b->decl) - || C_DECL_REGISTER (b->decl)) - error ("%<void%> as only parameter may not be qualified"); - - /* There cannot be an ellipsis. */ - if (ellipsis) - error ("%<void%> must be the only parameter"); + if (TREE_THIS_VOLATILE (parms) + || TREE_READONLY (parms) + || DECL_REGISTER (parms)) + error ("\"void\" as only parameter may not be qualified"); - arg_info->types = void_list_node; - return arg_info; + return tree_cons (0, 0, tree_cons (0, void_type_node, 0)); } - if (!ellipsis) - types = void_list_node; - - /* Break up the bindings list into parms, tags, types, and others; - apply sanity checks; purge the name-to-decl bindings. */ - while (b) + /* Sanity check all of the parameter declarations. */ + for (decl = parms; decl; decl = TREE_CHAIN (decl)) { - tree decl = b->decl; - tree type = TREE_TYPE (decl); - const char *keyword; + if (TREE_CODE (decl) != PARM_DECL) + abort (); + if (TREE_ASM_WRITTEN (decl)) + abort (); - switch (TREE_CODE (decl)) - { - case PARM_DECL: - if (b->id) - { - gcc_assert (I_SYMBOL_BINDING (b->id) == b); - I_SYMBOL_BINDING (b->id) = b->shadowed; - } + /* Since there is a prototype, args are passed in their + declared types. The back end may override this. */ + type = TREE_TYPE (decl); + DECL_ARG_TYPE (decl) = type; - /* Check for forward decls that never got their actual decl. */ - if (TREE_ASM_WRITTEN (decl)) - error ("parameter %q+D has just a forward declaration", decl); - /* Check for (..., void, ...) and issue an error. */ - else if (VOID_TYPE_P (type) && !DECL_NAME (decl)) - { - if (!gave_void_only_once_err) - { - error ("%<void%> must be the only parameter"); - gave_void_only_once_err = true; - } - } - else - { - /* Valid parameter, add it to the list. */ - TREE_CHAIN (decl) = parms; - parms = decl; - - /* Since there is a prototype, args are passed in their - declared types. The back end may override this later. */ - DECL_ARG_TYPE (decl) = type; - types = tree_cons (0, type, types); - } - break; + /* Check for (..., void, ...) and issue an error. */ + if (VOID_TYPE_P (type) && !DECL_NAME (decl) && !gave_void_only_once_err) + { + error ("\"void\" must be the only parameter"); + gave_void_only_once_err = true; + } - case ENUMERAL_TYPE: keyword = "enum"; goto tag; - case UNION_TYPE: keyword = "union"; goto tag; - case RECORD_TYPE: keyword = "struct"; goto tag; - tag: - /* Types may not have tag-names, in which case the type - appears in the bindings list with b->id NULL. */ - if (b->id) - { - gcc_assert (I_TAG_BINDING (b->id) == b); - I_TAG_BINDING (b->id) = b->shadowed; - } + type = build_tree_list (0, type); + *last_type = type; + last_type = &TREE_CHAIN (type); + } - /* Warn about any struct, union or enum tags defined in a - parameter list. The scope of such types is limited to - the parameter list, which is rarely if ever desirable - (it's impossible to call such a function with type- - correct arguments). An anonymous union parm type is - meaningful as a GNU extension, so don't warn for that. */ - if (TREE_CODE (decl) != UNION_TYPE || b->id != 0) - { - if (b->id) - /* The %s will be one of 'struct', 'union', or 'enum'. */ - warning (0, "%<%s %E%> declared inside parameter list", - keyword, b->id); - else - /* The %s will be one of 'struct', 'union', or 'enum'. */ - warning (0, "anonymous %s declared inside parameter list", - keyword); + /* Check the list of non-parameter decls for any forward parm decls + that never got real decls. */ + for (decl = others; decl; decl = TREE_CHAIN (decl)) + if (TREE_CODE (decl) == PARM_DECL) + { + if (!TREE_ASM_WRITTEN (decl)) + abort (); - if (!explained_incomplete_types) - { - warning (0, "its scope is only this definition or declaration," - " which is probably not what you want"); - explained_incomplete_types = true; - } - } + error ("%Jparameter \"%D\" has just a forward declaration", + decl, decl); + } - tags = tree_cons (b->id, decl, tags); - break; + /* Warn about any struct, union or enum tags defined within this + list. The scope of such types is limited to this declaration, + which is rarely if ever desirable (it's impossible to call such + a function with type-correct arguments). */ + for (decl = tags; decl; decl = TREE_CHAIN (decl)) + { + enum tree_code code = TREE_CODE (TREE_VALUE (decl)); + const char *keyword; + /* An anonymous union parm type is meaningful as a GNU extension. + So don't warn for that. */ + if (code == UNION_TYPE && TREE_PURPOSE (decl) == 0 && !pedantic) + continue; - case CONST_DECL: - case TYPE_DECL: - case FUNCTION_DECL: - /* CONST_DECLs appear here when we have an embedded enum, - and TYPE_DECLs appear here when we have an embedded struct - or union. No warnings for this - we already warned about the - type itself. FUNCTION_DECLs appear when there is an implicit - function declaration in the parameter list. */ - - TREE_CHAIN (decl) = others; - others = decl; - /* fall through */ + /* The keyword should not be translated. */ + switch (code) + { + case RECORD_TYPE: keyword = "struct"; break; + case UNION_TYPE: keyword = "union"; break; + case ENUMERAL_TYPE: keyword = "enum"; break; + default: abort (); + } - case ERROR_MARK: - /* error_mark_node appears here when we have an undeclared - variable. Just throw it away. */ - if (b->id) - { - gcc_assert (I_SYMBOL_BINDING (b->id) == b); - I_SYMBOL_BINDING (b->id) = b->shadowed; - } - break; + if (TREE_PURPOSE (decl)) + /* The first %s will be one of 'struct', 'union', or 'enum'. */ + warning ("\"%s %s\" declared inside parameter list", + keyword, IDENTIFIER_POINTER (TREE_PURPOSE (decl))); + else + /* The %s will be one of 'struct', 'union', or 'enum'. */ + warning ("anonymous %s declared inside parameter list", keyword); - /* Other things that might be encountered. */ - case LABEL_DECL: - case VAR_DECL: - default: - gcc_unreachable (); + if (! explained_incomplete_types) + { + warning ("its scope is only this definition or declaration," + " which is probably not what you want"); + explained_incomplete_types = true; } + } + - b = free_binding_and_advance (b); + if (void_at_end) + { + type = build_tree_list (0, void_type_node); + *last_type = type; } - arg_info->parms = parms; - arg_info->tags = tags; - arg_info->types = types; - arg_info->others = others; - arg_info->pending_sizes = get_pending_sizes (); - return arg_info; + list = tree_cons (parms, tags, types); + TREE_TYPE (list) = others; + return list; } /* Get the struct, enum or union (CODE says which) with tag NAME. - Define the tag as a forward-reference if it is not defined. - Return a c_typespec structure for the type specifier. */ + Define the tag as a forward-reference if it is not defined. */ -struct c_typespec -parser_xref_tag (enum tree_code code, tree name) +tree +xref_tag (enum tree_code code, tree name) { - struct c_typespec ret; /* If a cross reference is requested, look up the type already defined for this tag and return it. */ @@ -5215,12 +4761,8 @@ parser_xref_tag (enum tree_code code, tree name) this would not work properly if we return the reference found. (For example, with "struct foo" in an outer scope, "union foo;" must shadow that tag with a new one of union type.) */ - ret.kind = (ref ? ctsk_tagref : ctsk_tagfirstref); if (ref && TREE_CODE (ref) == code) - { - ret.spec = ref; - return ret; - } + return ref; /* If no such tag is yet defined, create a forward-reference node and record it as the "definition". @@ -5235,7 +4777,7 @@ parser_xref_tag (enum tree_code code, tree name) TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node); TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node); TYPE_USER_ALIGN (ref) = 0; - TYPE_UNSIGNED (ref) = 1; + TREE_UNSIGNED (ref) = 1; TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node); TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node); TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); @@ -5243,18 +4785,7 @@ parser_xref_tag (enum tree_code code, tree name) pushtag (name, ref); - ret.spec = ref; - return ret; -} - -/* Get the struct, enum or union (CODE says which) with tag NAME. - Define the tag as a forward-reference if it is not defined. - Return a tree for the type. */ - -tree -xref_tag (enum tree_code code, tree name) -{ - return parser_xref_tag (code, name).spec; + return ref; } /* Make sure that the tag NAME is defined *in the current scope* @@ -5274,18 +4805,20 @@ start_struct (enum tree_code code, tree name) if (ref && TREE_CODE (ref) == code) { if (TYPE_SIZE (ref)) - { + { if (code == UNION_TYPE) - error ("redefinition of %<union %E%>", name); - else - error ("redefinition of %<struct %E%>", name); + error ("redefinition of `union %s'", IDENTIFIER_POINTER (name)); + else + error ("redefinition of `struct %s'", IDENTIFIER_POINTER (name)); } else if (C_TYPE_BEING_DEFINED (ref)) { if (code == UNION_TYPE) - error ("nested redefinition of %<union %E%>", name); - else - error ("nested redefinition of %<struct %E%>", name); + error ("nested redefinition of `union %s'", + IDENTIFIER_POINTER (name)); + else + error ("nested redefinition of `struct %s'", + IDENTIFIER_POINTER (name)); } } else @@ -5301,7 +4834,7 @@ start_struct (enum tree_code code, tree name) return ref; } -/* Process the specs, declarator and width (NULL if omitted) +/* Process the specs, declarator (NULL if omitted) and width (NULL if omitted) of a structure component, returning a FIELD_DECL node. WIDTH is non-NULL for bit-fields only, and is an INTEGER_CST node. @@ -5310,13 +4843,11 @@ start_struct (enum tree_code code, tree name) are ultimately passed to `build_struct' to make the RECORD_TYPE node. */ tree -grokfield (struct c_declarator *declarator, struct c_declspecs *declspecs, - tree width) +grokfield (tree declarator, tree declspecs, tree width) { tree value; - if (declarator->kind == cdk_id && declarator->u.id == NULL_TREE - && width == NULL_TREE) + if (declarator == NULL_TREE && width == NULL_TREE) { /* This is an unnamed decl. @@ -5337,33 +4868,30 @@ grokfield (struct c_declarator *declarator, struct c_declspecs *declspecs, took this from Plan 9 or if it was an accident of implementation that took root before someone noticed the bug... */ - tree type = declspecs->type; - bool type_ok = (TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == UNION_TYPE); - bool ok = false; + tree type = TREE_VALUE (declspecs); - if (type_ok - && (flag_ms_extensions || !declspecs->typedef_p)) + if (flag_ms_extensions && TREE_CODE (type) == TYPE_DECL) + type = TREE_TYPE (type); + if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE) { if (flag_ms_extensions) - ok = true; + ; /* ok */ else if (flag_iso) - ok = false; + goto warn_unnamed_field; else if (TYPE_NAME (type) == NULL) - ok = true; + ; /* ok */ else - ok = false; + goto warn_unnamed_field; } - if (!ok) + else { - pedwarn ("declaration does not declare anything"); + warn_unnamed_field: + warning ("declaration does not declare anything"); return NULL_TREE; } - if (pedantic) - pedwarn ("ISO C doesn%'t support unnamed structs/unions"); } - value = grokdeclarator (declarator, declspecs, FIELD, false, + value = grokdeclarator (declarator, declspecs, FIELD, 0, width ? &width : NULL); finish_decl (value, NULL_TREE, NULL_TREE); @@ -5403,7 +4931,7 @@ detect_field_duplicates (tree fieldlist) for (y = fieldlist; y != x; y = TREE_CHAIN (y)) if (DECL_NAME (y) == DECL_NAME (x)) { - error ("duplicate member %q+D", x); + error ("%Jduplicate member '%D'", x, x); DECL_NAME (x) = NULL_TREE; } } @@ -5419,7 +4947,7 @@ detect_field_duplicates (tree fieldlist) slot = htab_find_slot (htab, y, INSERT); if (*slot) { - error ("duplicate member %q+D", x); + error ("%Jduplicate member '%D'", x, x); DECL_NAME (x) = NULL_TREE; } *slot = y; @@ -5437,7 +4965,7 @@ tree finish_struct (tree t, tree fieldlist, tree attributes) { tree x; - bool toplevel = file_scope == current_scope; + int toplevel = global_scope == current_scope; int saw_named_field; /* If this type was previously laid out as a forward reference, @@ -5447,6 +4975,19 @@ finish_struct (tree t, tree fieldlist, tree attributes) decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); + /* Nameless union parm types are useful as GCC extension. */ + if (! (TREE_CODE (t) == UNION_TYPE && TYPE_NAME (t) == 0) && !pedantic) + /* Otherwise, warn about any struct or union def. in parmlist. */ + if (in_parm_level_p ()) + { + if (pedantic) + pedwarn ("%s defined inside parms", + TREE_CODE (t) == UNION_TYPE ? _("union") : _("structure")); + else + warning ("%s defined inside parms", + TREE_CODE (t) == UNION_TYPE ? _("union") : _("structure")); + } + if (pedantic) { for (x = fieldlist; x; x = TREE_CHAIN (x)) @@ -5454,41 +4995,21 @@ finish_struct (tree t, tree fieldlist, tree attributes) break; if (x == 0) - { - if (TREE_CODE (t) == UNION_TYPE) - { - if (fieldlist) - pedwarn ("union has no named members"); - else - pedwarn ("union has no members"); - } - else - { - if (fieldlist) - pedwarn ("struct has no named members"); - else - pedwarn ("struct has no members"); - } - } + pedwarn ("%s has no %s", + TREE_CODE (t) == UNION_TYPE ? _("union") : _("struct"), + fieldlist ? _("named members") : _("members")); } /* Install struct as DECL_CONTEXT of each field decl. - Also process specified field sizes, found in the DECL_INITIAL, - storing 0 there after the type has been changed to precision equal - to its width, rather than the precision of the specified standard - type. (Correct layout requires the original type to have been preserved - until now.) */ + Also process specified field sizes,m which is found in the DECL_INITIAL. + Store 0 there, except for ": 0" fields (so we can find them + and delete them, below). */ saw_named_field = 0; for (x = fieldlist; x; x = TREE_CHAIN (x)) { - if (TREE_TYPE (x) == error_mark_node) - continue; - DECL_CONTEXT (x) = t; - - if (TYPE_PACKED (t) && TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT) - DECL_PACKED (x) = 1; + DECL_PACKED (x) |= TYPE_PACKED (t); /* If any field is const, the structure type is pseudo-const. */ if (TREE_READONLY (x)) @@ -5521,6 +5042,8 @@ finish_struct (tree t, tree fieldlist, tree attributes) SET_DECL_C_BIT_FIELD (x); } + DECL_INITIAL (x) = 0; + /* Detect flexible array member in an invalid context. */ if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE @@ -5537,7 +5060,7 @@ finish_struct (tree t, tree fieldlist, tree attributes) error ("%Jflexible array member not at end of struct", x); TREE_TYPE (x) = error_mark_node; } - else if (!saw_named_field) + else if (! saw_named_field) { error ("%Jflexible array member in otherwise empty struct", x); TREE_TYPE (x) = error_mark_node; @@ -5561,24 +5084,12 @@ finish_struct (tree t, tree fieldlist, tree attributes) layout_type (t); - /* Give bit-fields their proper types. */ + /* Delete all zero-width bit-fields from the fieldlist. */ { tree *fieldlistp = &fieldlist; while (*fieldlistp) - if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp) - && TREE_TYPE (*fieldlistp) != error_mark_node) - { - unsigned HOST_WIDE_INT width - = tree_low_cst (DECL_INITIAL (*fieldlistp), 1); - tree type = TREE_TYPE (*fieldlistp); - if (width != TYPE_PRECISION (type)) - { - TREE_TYPE (*fieldlistp) - = c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type)); - DECL_MODE (*fieldlistp) = TYPE_MODE (TREE_TYPE (*fieldlistp)); - } - DECL_INITIAL (*fieldlistp) = 0; - } + if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp)) + *fieldlistp = TREE_CHAIN (*fieldlistp); else fieldlistp = &TREE_CHAIN (*fieldlistp); } @@ -5596,46 +5107,45 @@ finish_struct (tree t, tree fieldlist, tree attributes) for (x = fieldlist; x; x = TREE_CHAIN (x)) { - if (len > 15 || DECL_NAME (x) == NULL) - break; - len += 1; + if (len > 15 || DECL_NAME (x) == NULL) + break; + len += 1; } if (len > 15) { - tree *field_array; - struct lang_type *space; - struct sorted_fields_type *space2; + tree *field_array; + struct lang_type *space; + struct sorted_fields_type *space2; - len += list_length (x); + len += list_length (x); - /* Use the same allocation policy here that make_node uses, to - ensure that this lives as long as the rest of the struct decl. - All decls in an inline function need to be saved. */ + /* Use the same allocation policy here that make_node uses, to + ensure that this lives as long as the rest of the struct decl. + All decls in an inline function need to be saved. */ - space = GGC_CNEW (struct lang_type); - space2 = GGC_NEWVAR (struct sorted_fields_type, - sizeof (struct sorted_fields_type) + len * sizeof (tree)); + space = ggc_alloc (sizeof (struct lang_type)); + space2 = ggc_alloc (sizeof (struct sorted_fields_type) + len * sizeof (tree)); - len = 0; + len = 0; space->s = space2; field_array = &space2->elts[0]; - for (x = fieldlist; x; x = TREE_CHAIN (x)) - { - field_array[len++] = x; - - /* If there is anonymous struct or union, break out of the loop. */ - if (DECL_NAME (x) == NULL) - break; - } - /* Found no anonymous struct/union. Add the TYPE_LANG_SPECIFIC. */ - if (x == NULL) - { - TYPE_LANG_SPECIFIC (t) = space; - TYPE_LANG_SPECIFIC (t)->s->len = len; - field_array = TYPE_LANG_SPECIFIC (t)->s->elts; - qsort (field_array, len, sizeof (tree), field_decl_cmp); - } + for (x = fieldlist; x; x = TREE_CHAIN (x)) + { + field_array[len++] = x; + + /* If there is anonymous struct or union, break out of the loop. */ + if (DECL_NAME (x) == NULL) + break; + } + /* Found no anonymous struct/union. Add the TYPE_LANG_SPECIFIC. */ + if (x == NULL) + { + TYPE_LANG_SPECIFIC (t) = space; + TYPE_LANG_SPECIFIC (t)->s->len = len; + field_array = TYPE_LANG_SPECIFIC (t)->s->elts; + qsort (field_array, len, sizeof (tree), field_decl_cmp); + } } } @@ -5643,6 +5153,8 @@ finish_struct (tree t, tree fieldlist, tree attributes) { TYPE_FIELDS (x) = TYPE_FIELDS (t); TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t); + TYPE_ALIGN (x) = TYPE_ALIGN (t); + TYPE_USER_ALIGN (x) = TYPE_USER_ALIGN (t); C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t); C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t); C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); @@ -5655,7 +5167,7 @@ finish_struct (tree t, tree fieldlist, tree attributes) && (!TYPE_FIELDS (t) || TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t)))) { TYPE_TRANSPARENT_UNION (t) = 0; - warning (0, "union cannot be made transparent"); + warning ("union cannot be made transparent"); } /* If this structure or union completes the type of any previous @@ -5672,8 +5184,8 @@ finish_struct (tree t, tree fieldlist, tree attributes) layout_decl (decl, 0); if (c_dialect_objc ()) objc_check_decl (decl); - rest_of_decl_compilation (decl, toplevel, 0); - if (!toplevel) + rest_of_decl_compilation (decl, NULL, toplevel, 0); + if (! toplevel) expand_decl (decl); } } @@ -5682,12 +5194,6 @@ finish_struct (tree t, tree fieldlist, tree attributes) /* Finish debugging output for this type. */ rest_of_type_compilation (t, toplevel); - /* If we're inside a function proper, i.e. not file-scope and not still - parsing parameters, then arrange for the size of a variable sized type - to be bound now. */ - if (cur_stmt_list && variably_modified_type_p (t, NULL_TREE)) - add_stmt (build_stmt (DECL_EXPR, build_decl (TYPE_DECL, NULL, t))); - return t; } @@ -5726,14 +5232,14 @@ start_enum (tree name) } if (C_TYPE_BEING_DEFINED (enumtype)) - error ("nested redefinition of %<enum %E%>", name); + error ("nested redefinition of `enum %s'", IDENTIFIER_POINTER (name)); C_TYPE_BEING_DEFINED (enumtype) = 1; if (TYPE_VALUES (enumtype) != 0) { /* This enum is a named one that has been declared already. */ - error ("redeclaration of %<enum %E%>", name); + error ("redeclaration of `enum %s'", IDENTIFIER_POINTER (name)); /* Completely replace its old definition. The old enumerators remain defined, however. */ @@ -5759,10 +5265,12 @@ tree finish_enum (tree enumtype, tree values, tree attributes) { tree pair, tem; - tree minnode = 0, maxnode = 0; + tree minnode = 0, maxnode = 0, enum_value_type; int precision, unsign; - bool toplevel = (file_scope == current_scope); - struct lang_type *lt; + int toplevel = (global_scope == current_scope); + + if (in_parm_level_p ()) + warning ("enum defined inside parms"); decl_attributes (&enumtype, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); @@ -5790,22 +5298,28 @@ finish_enum (tree enumtype, tree values, tree attributes) unsign = (tree_int_cst_sgn (minnode) >= 0); precision = MAX (min_precision (minnode, unsign), min_precision (maxnode, unsign)); - if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node)) { - tem = c_common_type_for_size (precision, unsign); - if (tem == NULL) + tree narrowest = c_common_type_for_size (precision, unsign); + if (narrowest == 0) { - warning (0, "enumeration values exceed range of largest integer"); - tem = long_long_integer_type_node; + warning ("enumeration values exceed range of largest integer"); + narrowest = long_long_integer_type_node; } + + precision = TYPE_PRECISION (narrowest); } else - tem = unsign ? unsigned_type_node : integer_type_node; + precision = TYPE_PRECISION (integer_type_node); - TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); - TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); - TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); + if (precision == TYPE_PRECISION (integer_type_node)) + enum_value_type = c_common_type_for_size (precision, 0); + else + enum_value_type = enumtype; + + TYPE_MIN_VALUE (enumtype) = minnode; + TYPE_MAX_VALUE (enumtype) = maxnode; + TREE_UNSIGNED (enumtype) = unsign; TYPE_SIZE (enumtype) = 0; /* If the precision of the type was specific with an attribute and it @@ -5816,7 +5330,7 @@ finish_enum (tree enumtype, tree values, tree attributes) error ("specified mode too small for enumeral values"); } else - TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); + TYPE_PRECISION (enumtype) = precision; layout_type (enumtype); @@ -5832,7 +5346,6 @@ finish_enum (tree enumtype, tree values, tree attributes) for (pair = values; pair; pair = TREE_CHAIN (pair)) { tree enu = TREE_PURPOSE (pair); - tree ini = DECL_INITIAL (enu); TREE_TYPE (enu) = enumtype; @@ -5843,27 +5356,18 @@ finish_enum (tree enumtype, tree values, tree attributes) when comparing integers with enumerators that fit in the int range. When -pedantic is given, build_enumerator() would have already taken care of those that don't fit. */ - if (int_fits_type_p (ini, integer_type_node)) - tem = integer_type_node; + if (int_fits_type_p (DECL_INITIAL (enu), enum_value_type)) + DECL_INITIAL (enu) = convert (enum_value_type, DECL_INITIAL (enu)); else - tem = enumtype; - ini = convert (tem, ini); + DECL_INITIAL (enu) = convert (enumtype, DECL_INITIAL (enu)); - DECL_INITIAL (enu) = ini; TREE_PURPOSE (pair) = DECL_NAME (enu); - TREE_VALUE (pair) = ini; + TREE_VALUE (pair) = DECL_INITIAL (enu); } TYPE_VALUES (enumtype) = values; } - /* Record the min/max values so that we can warn about bit-field - enumerations that are too small for the values. */ - lt = GGC_CNEW (struct lang_type); - lt->enum_min = minnode; - lt->enum_max = maxnode; - TYPE_LANG_SPECIFIC (enumtype) = lt; - /* Fix up all variant types of this enum type. */ for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem)) { @@ -5878,8 +5382,7 @@ finish_enum (tree enumtype, tree values, tree attributes) TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype); TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype); TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype); - TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); - TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); + TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype); } /* Finish debugging output for this type. */ @@ -5900,22 +5403,22 @@ build_enumerator (tree name, tree value) /* Validate and default VALUE. */ + /* Remove no-op casts from the value. */ + if (value) + STRIP_TYPE_NOPS (value); + if (value != 0) { - /* Don't issue more errors for error_mark_node (i.e. an - undeclared identifier) - just ignore the value expression. */ - if (value == error_mark_node) - value = 0; - else if (!INTEGRAL_TYPE_P (TREE_TYPE (value)) - || TREE_CODE (value) != INTEGER_CST) + if (TREE_CODE (value) == INTEGER_CST) { - error ("enumerator value for %qE is not an integer constant", name); - value = 0; + value = default_conversion (value); + constant_expression_warning (value); } else { - value = default_conversion (value); - constant_expression_warning (value); + error ("enumerator value for `%s' not integer constant", + IDENTIFIER_POINTER (name)); + value = 0; } } @@ -5929,11 +5432,9 @@ build_enumerator (tree name, tree value) error ("overflow in enumeration values"); } - if (pedantic && !int_fits_type_p (value, integer_type_node)) + if (pedantic && ! int_fits_type_p (value, integer_type_node)) { - pedwarn ("ISO C restricts enumerator values to range of %<int%>"); - /* XXX This causes -pedantic to change the meaning of the program. - Remove? -zw 2004-03-15 */ + pedwarn ("ISO C restricts enumerator values to range of `int'"); value = convert (integer_type_node, value); } @@ -5948,7 +5449,7 @@ build_enumerator (tree name, tree value) TYPE_PRECISION (integer_type_node)), (TYPE_PRECISION (type) >= TYPE_PRECISION (integer_type_node) - && TYPE_UNSIGNED (type))); + && TREE_UNSIGNED (type))); decl = build_decl (CONST_DECL, name, type); DECL_INITIAL (decl) = convert (type, value); @@ -5971,47 +5472,30 @@ build_enumerator (tree name, tree value) yyparse to report a parse error. */ int -start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, - tree attributes) +start_function (tree declspecs, tree declarator, tree attributes) { tree decl1, old_decl; - tree restype, resdecl; - struct c_label_context_se *nstack_se; - struct c_label_context_vm *nstack_vm; + tree restype; + int old_immediate_size_expand = immediate_size_expand; current_function_returns_value = 0; /* Assume, until we see it does. */ current_function_returns_null = 0; current_function_returns_abnormally = 0; warn_about_return_type = 0; current_extern_inline = 0; - c_switch_stack = NULL; - - nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se); - nstack_se->labels_def = NULL; - nstack_se->labels_used = NULL; - nstack_se->next = label_context_stack_se; - label_context_stack_se = nstack_se; - - nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm); - nstack_vm->labels_def = NULL; - nstack_vm->labels_used = NULL; - nstack_vm->scope = 0; - nstack_vm->next = label_context_stack_vm; - label_context_stack_vm = nstack_vm; + c_in_iteration_stmt = 0; + c_in_case_stmt = 0; - /* Indicate no valid break/continue context by setting these variables - to some non-null, non-label value. We'll notice and emit the proper - error message in c_finish_bc_stmt. */ - c_break_label = c_cont_label = size_zero_node; + /* Don't expand any sizes in the return type of the function. */ + immediate_size_expand = 0; - decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL); + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL); /* If the declarator is not suitable for a function definition, cause a syntax error. */ if (decl1 == 0) { - label_context_stack_se = label_context_stack_se->next; - label_context_stack_vm = label_context_stack_vm->next; + immediate_size_expand = old_immediate_size_expand; return 0; } @@ -6020,8 +5504,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, if (DECL_DECLARED_INLINE_P (decl1) && DECL_UNINLINABLE (decl1) && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl1))) - warning (OPT_Wattributes, "inline function %q+D given attribute noinline", - decl1); + warning ("%Jinline function '%D' given attribute noinline", decl1, decl1); announce_function (decl1); @@ -6035,105 +5518,63 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, } if (warn_about_return_type) - pedwarn_c99 ("return type defaults to %<int%>"); + pedwarn_c99 ("return type defaults to `int'"); + + /* Save the parm names or decls from this function's declarator + where store_parm_decls will find them. */ + current_function_parms = last_function_parms; + current_function_parm_tags = last_function_parm_tags; + current_function_parm_others = last_function_parm_others; /* Make the init_value nonzero so pushdecl knows this is not tentative. - error_mark_node is replaced below (in pop_scope) with the BLOCK. */ + error_mark_node is replaced below (in poplevel) with the BLOCK. */ DECL_INITIAL (decl1) = error_mark_node; /* If this definition isn't a prototype and we had a prototype declaration - before, copy the arg type info from that prototype. */ - old_decl = lookup_name_in_scope (DECL_NAME (decl1), current_scope); - if (old_decl && TREE_CODE (old_decl) != FUNCTION_DECL) - old_decl = 0; - current_function_prototype_locus = UNKNOWN_LOCATION; - current_function_prototype_built_in = false; - current_function_prototype_arg_types = NULL_TREE; - if (TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0) - { - if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE - && comptypes (TREE_TYPE (TREE_TYPE (decl1)), - TREE_TYPE (TREE_TYPE (old_decl)))) - { - TREE_TYPE (decl1) = composite_type (TREE_TYPE (old_decl), - TREE_TYPE (decl1)); - current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl); - current_function_prototype_built_in - = C_DECL_BUILTIN_PROTOTYPE (old_decl); - current_function_prototype_arg_types - = TYPE_ARG_TYPES (TREE_TYPE (decl1)); - } - if (TREE_PUBLIC (decl1)) - { - /* If there is an external prototype declaration of this - function, record its location but do not copy information - to this decl. This may be an invisible declaration - (built-in or in a scope which has finished) or simply - have more refined argument types than any declaration - found above. */ - struct c_binding *b; - for (b = I_SYMBOL_BINDING (DECL_NAME (decl1)); b; b = b->shadowed) - if (B_IN_SCOPE (b, external_scope)) - break; - if (b) - { - tree ext_decl, ext_type; - ext_decl = b->decl; - ext_type = b->type ? b->type : TREE_TYPE (ext_decl); - if (TREE_CODE (ext_type) == FUNCTION_TYPE - && comptypes (TREE_TYPE (TREE_TYPE (decl1)), - TREE_TYPE (ext_type))) - { - current_function_prototype_locus - = DECL_SOURCE_LOCATION (ext_decl); - current_function_prototype_built_in - = C_DECL_BUILTIN_PROTOTYPE (ext_decl); - current_function_prototype_arg_types - = TYPE_ARG_TYPES (ext_type); - } - } - } + before, copy the arg type info from that prototype. + But not if what we had before was a builtin function. */ + old_decl = lookup_name_current_level (DECL_NAME (decl1)); + if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE + && !DECL_BUILT_IN (old_decl) + && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1))) + == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (old_decl)))) + && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0) + { + TREE_TYPE (decl1) = TREE_TYPE (old_decl); + current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl); } /* Optionally warn of old-fashioned def with no previous prototype. */ if (warn_strict_prototypes - && old_decl != error_mark_node && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0 && C_DECL_ISNT_PROTOTYPE (old_decl)) - warning (OPT_Wstrict_prototypes, - "function declaration isn%'t a prototype"); + warning ("function declaration isn't a prototype"); /* Optionally warn of any global def with no previous prototype. */ else if (warn_missing_prototypes - && old_decl != error_mark_node && TREE_PUBLIC (decl1) - && !MAIN_NAME_P (DECL_NAME (decl1)) + && ! MAIN_NAME_P (DECL_NAME (decl1)) && C_DECL_ISNT_PROTOTYPE (old_decl)) - warning (OPT_Wmissing_prototypes, "no previous prototype for %q+D", decl1); + warning ("%Jno previous prototype for '%D'", decl1, decl1); /* Optionally warn of any def with no previous prototype if the function has already been used. */ else if (warn_missing_prototypes - && old_decl != 0 - && old_decl != error_mark_node - && TREE_USED (old_decl) + && old_decl != 0 && TREE_USED (old_decl) && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) == 0) - warning (OPT_Wmissing_prototypes, - "%q+D was used with no prototype before its definition", decl1); + warning ("%J'%D' was used with no prototype before its definition", + decl1, decl1); /* Optionally warn of any global def with no previous declaration. */ else if (warn_missing_declarations && TREE_PUBLIC (decl1) && old_decl == 0 - && !MAIN_NAME_P (DECL_NAME (decl1))) - warning (OPT_Wmissing_declarations, "no previous declaration for %q+D", - decl1); + && ! MAIN_NAME_P (DECL_NAME (decl1))) + warning ("%Jno previous declaration for '%D'", decl1, decl1); /* Optionally warn of any def with no previous declaration if the function has already been used. */ else if (warn_missing_declarations - && old_decl != 0 - && old_decl != error_mark_node - && TREE_USED (old_decl) + && old_decl != 0 && TREE_USED (old_decl) && C_DECL_IMPLICIT (old_decl)) - warning (OPT_Wmissing_declarations, - "%q+D was used with no declaration before its definition", decl1); + warning ("%J`%D' was used with no declaration before its definition", + decl1, decl1); /* This is a definition, not a reference. So normally clear DECL_EXTERNAL. @@ -6141,30 +5582,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, except for defining how to inline. So set DECL_EXTERNAL in that case. */ DECL_EXTERNAL (decl1) = current_extern_inline; - /* C99 specified different behaviour for non-static inline - functions, compared with the traditional GNU behaviour. We don't - support the C99 behaviour, but we do warn about non-static inline - functions here. The warning can be disabled via an explicit use - of -fgnu89-inline, or by using the gnu_inline attribute. */ - if (DECL_DECLARED_INLINE_P (decl1) - && TREE_PUBLIC (decl1) - && flag_isoc99 - && flag_gnu89_inline != 1 - && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl1)) - && diagnostic_report_warnings_p ()) - { - static bool info = false; - - warning (0, "C99 inline functions are not supported; using GNU89"); - if (!info) - { - warning (0, - "to disable this warning use -fgnu89-inline or " - "the gnu_inline function attribute"); - info = true; - } - } - /* This function exists in static storage. (This does not mean `static' in the C sense!) */ TREE_STATIC (decl1) = 1; @@ -6173,12 +5590,15 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, if (current_function_decl != 0) TREE_PUBLIC (decl1) = 0; +#ifdef ENABLE_CHECKING /* This is the earliest point at which we might know the assembler name of the function. Thus, if it's set before this, die horribly. */ - gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl1)); + if (DECL_ASSEMBLER_NAME_SET_P (decl1)) + abort (); +#endif /* If #pragma weak was used, mark the decl weak now. */ - if (current_scope == file_scope) + if (current_scope == global_scope) maybe_apply_pragma_weak (decl1); /* Warn for unlikely, improbable, or stupid declarations of `main'. */ @@ -6189,7 +5609,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1))) != integer_type_node) - pedwarn ("return type of %q+D is not %<int%>", decl1); + pedwarn ("%Jreturn type of '%D' is not `int'", decl1, decl1); for (args = TYPE_ARG_TYPES (TREE_TYPE (decl1)); args; args = TREE_CHAIN (args)) @@ -6204,7 +5624,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, { case 1: if (TYPE_MAIN_VARIANT (type) != integer_type_node) - pedwarn ("first argument of %q+D should be %<int%>", decl1); + pedwarn ("%Jfirst argument of '%D' should be `int'", + decl1, decl1); break; case 2: @@ -6212,8 +5633,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) != char_type_node)) - pedwarn ("second argument of %q+D should be %<char **%>", - decl1); + pedwarn ("%Jsecond argument of '%D' should be 'char **'", + decl1, decl1); break; case 3: @@ -6221,8 +5642,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) != char_type_node)) - pedwarn ("third argument of %q+D should probably be " - "%<char **%>", decl1); + pedwarn ("%Jthird argument of '%D' should probably be " + "'char **'", decl1, decl1); break; } } @@ -6231,10 +5652,10 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, argument because it's only mentioned in an appendix of the standard. */ if (argct > 0 && (argct < 2 || argct > 3)) - pedwarn ("%q+D takes only zero or two arguments", decl1); + pedwarn ("%J'%D' takes only zero or two arguments", decl1, decl1); - if (!TREE_PUBLIC (decl1)) - pedwarn ("%q+D is normally a non-static function", decl1); + if (! TREE_PUBLIC (decl1)) + pedwarn ("%J'%D' is normally a non-static function", decl1, decl1); } /* Record the decl so that the function name is defined. @@ -6243,26 +5664,32 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, current_function_decl = pushdecl (decl1); - push_scope (); + pushlevel (0); declare_parm_level (); + make_decl_rtl (current_function_decl, NULL); + restype = TREE_TYPE (TREE_TYPE (current_function_decl)); /* Promote the value to int before returning it. */ if (c_promoting_integer_type_p (restype)) { /* It retains unsignedness if not really getting wider. */ - if (TYPE_UNSIGNED (restype) + if (TREE_UNSIGNED (restype) && (TYPE_PRECISION (restype) == TYPE_PRECISION (integer_type_node))) restype = unsigned_type_node; else restype = integer_type_node; } + DECL_RESULT (current_function_decl) + = build_decl (RESULT_DECL, NULL_TREE, restype); - resdecl = build_decl (RESULT_DECL, NULL_TREE, restype); - DECL_ARTIFICIAL (resdecl) = 1; - DECL_IGNORED_P (resdecl) = 1; - DECL_RESULT (current_function_decl) = resdecl; + /* If this fcn was already referenced via a block-scope `extern' decl + (or an implicit decl), propagate certain information about the usage. */ + if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl))) + TREE_ADDRESSABLE (current_function_decl) = 1; + + immediate_size_expand = old_immediate_size_expand; start_fname_decls (); @@ -6274,78 +5701,98 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, need only record them as in effect and complain if any redundant old-style parm decls were written. */ static void -store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info) +store_parm_decls_newstyle (void) { - tree decl; + tree decl, last; + tree fndecl = current_function_decl; + tree parms = current_function_parms; + tree tags = current_function_parm_tags; + tree others = current_function_parm_others; - if (current_scope->bindings) + if (current_scope->parms || current_scope->names || current_scope->tags) { error ("%Jold-style parameter declarations in prototyped " "function definition", fndecl); /* Get rid of the old-style declarations. */ - pop_scope (); - push_scope (); - } - /* Don't issue this warning for nested functions, and don't issue this - warning if we got here because ARG_INFO_TYPES was error_mark_node - (this happens when a function definition has just an ellipsis in - its parameter list). */ - else if (!in_system_header && !current_function_scope - && arg_info->types != error_mark_node) - warning (OPT_Wtraditional, - "%Jtraditional C rejects ISO C style function definitions", - fndecl); + poplevel (0, 0, 0); + pushlevel (0); + } /* Now make all the parameter declarations visible in the function body. We can bypass most of the grunt work of pushdecl. */ - for (decl = arg_info->parms; decl; decl = TREE_CHAIN (decl)) + for (last = 0, decl = parms; decl; last = decl, decl = TREE_CHAIN (decl)) { DECL_CONTEXT (decl) = current_function_decl; - if (DECL_NAME (decl)) + if (DECL_NAME (decl) == 0) + error ("%Jparameter name omitted", decl); + else { - bind (DECL_NAME (decl), decl, current_scope, - /*invisible=*/false, /*nested=*/false); - if (!TREE_USED (decl)) - warn_if_shadowing (decl); + if (IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl))) + current_scope->shadowed + = tree_cons (DECL_NAME (decl), + IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)), + current_scope->shadowed); + IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)) = decl; } - else - error ("%Jparameter name omitted", decl); } + current_scope->parms = parms; + current_scope->parms_last = last; /* Record the parameter list in the function declaration. */ - DECL_ARGUMENTS (fndecl) = arg_info->parms; + DECL_ARGUMENTS (fndecl) = parms; /* Now make all the ancillary declarations visible, likewise. */ - for (decl = arg_info->others; decl; decl = TREE_CHAIN (decl)) + for (last = 0, decl = others; decl; last = decl, decl = TREE_CHAIN (decl)) { DECL_CONTEXT (decl) = current_function_decl; - if (DECL_NAME (decl)) - bind (DECL_NAME (decl), decl, current_scope, - /*invisible=*/false, /*nested=*/false); + if (DECL_NAME (decl) + && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) != void_type_node) + { + if (IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl))) + current_scope->shadowed + = tree_cons (DECL_NAME (decl), + IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)), + current_scope->shadowed); + IDENTIFIER_SYMBOL_VALUE (DECL_NAME (decl)) = decl; + } } + current_scope->names = others; + current_scope->names_last = last; /* And all the tag declarations. */ - for (decl = arg_info->tags; decl; decl = TREE_CHAIN (decl)) + for (decl = tags; decl; decl = TREE_CHAIN (decl)) if (TREE_PURPOSE (decl)) - bind (TREE_PURPOSE (decl), TREE_VALUE (decl), current_scope, - /*invisible=*/false, /*nested=*/false); + { + if (IDENTIFIER_TAG_VALUE (TREE_PURPOSE (decl))) + current_scope->shadowed_tags + = tree_cons (TREE_PURPOSE (decl), + IDENTIFIER_SYMBOL_VALUE (TREE_PURPOSE (decl)), + current_scope->shadowed_tags); + IDENTIFIER_TAG_VALUE (TREE_PURPOSE (decl)) = TREE_VALUE (decl); + } + current_scope->tags = tags; } /* Subroutine of store_parm_decls which handles old-style function definitions (separate parameter list and declarations). */ static void -store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) +store_parm_decls_oldstyle (void) { - struct c_binding *b; tree parm, decl, last; - tree parmids = arg_info->parms; - struct pointer_set_t *seen_args = pointer_set_create (); + tree fndecl = current_function_decl; + + /* This is the identifier list from the function declarator. */ + tree parmids = current_function_parms; - if (!in_system_header) - warning (OPT_Wold_style_definition, "%Jold-style function definition", - fndecl); + /* We use DECL_WEAK as a flag to show which parameters have been + seen already, since it is not used on PARM_DECL. */ +#ifdef ENABLE_CHECKING + for (parm = current_scope->parms; parm; parm = TREE_CHAIN (parm)) + if (DECL_WEAK (parm)) + abort (); +#endif /* Match each formal parameter name with its declaration. Save each decl in the appropriate TREE_PURPOSE slot of the parmids chain. */ @@ -6358,18 +5805,17 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) continue; } - b = I_SYMBOL_BINDING (TREE_VALUE (parm)); - if (b && B_IN_CURRENT_SCOPE (b)) + decl = IDENTIFIER_SYMBOL_VALUE (TREE_VALUE (parm)); + if (decl && DECL_CONTEXT (decl) == fndecl) { - decl = b->decl; /* If we got something other than a PARM_DECL it is an error. */ if (TREE_CODE (decl) != PARM_DECL) - error ("%q+D declared as a non-parameter", decl); + error ("%J\"%D\" declared as a non-parameter", decl, decl); /* If the declaration is already marked, we have a duplicate name. Complain and ignore the duplicate. */ - else if (pointer_set_contains (seen_args, decl)) + else if (DECL_WEAK (decl)) { - error ("multiple parameters named %q+D", decl); + error ("%Jmultiple parameters named \"%D\"", decl, decl); TREE_PURPOSE (parm) = 0; continue; } @@ -6377,12 +5823,11 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) an int. */ else if (VOID_TYPE_P (TREE_TYPE (decl))) { - error ("parameter %q+D declared with void type", decl); + error ("%Jparameter \"%D\" declared void", decl, decl); TREE_TYPE (decl) = integer_type_node; DECL_ARG_TYPE (decl) = integer_type_node; layout_decl (decl, 0); } - warn_if_shadowing (decl); } /* If no declaration found, default to int. */ else @@ -6391,37 +5836,32 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) DECL_ARG_TYPE (decl) = TREE_TYPE (decl); DECL_SOURCE_LOCATION (decl) = DECL_SOURCE_LOCATION (fndecl); pushdecl (decl); - warn_if_shadowing (decl); if (flag_isoc99) - pedwarn ("type of %q+D defaults to %<int%>", decl); + pedwarn ("%Jtype of \"%D\" defaults to \"int\"", decl, decl); else if (extra_warnings) - warning (OPT_Wextra, "type of %q+D defaults to %<int%>", decl); + warning ("%Jtype of \"%D\" defaults to \"int\"", decl, decl); } TREE_PURPOSE (parm) = decl; - pointer_set_insert (seen_args, decl); + DECL_WEAK (decl) = 1; } /* Now examine the parms chain for incomplete declarations and declarations with no corresponding names. */ - for (b = current_scope->bindings; b; b = b->prev) + for (parm = current_scope->parms; parm; parm = TREE_CHAIN (parm)) { - parm = b->decl; - if (TREE_CODE (parm) != PARM_DECL) - continue; - - if (TREE_TYPE (parm) != error_mark_node - && !COMPLETE_TYPE_P (TREE_TYPE (parm))) + if (!COMPLETE_TYPE_P (TREE_TYPE (parm))) { - error ("parameter %q+D has incomplete type", parm); + error ("%Jparameter \"%D\" has incomplete type", parm, parm); TREE_TYPE (parm) = error_mark_node; } - if (!pointer_set_contains (seen_args, parm)) + if (! DECL_WEAK (parm)) { - error ("declaration for parameter %q+D but no such parameter", parm); + error ("%Jdeclaration for parameter \"%D\" but no such parameter", + parm, parm); /* Pretend the parameter was not missing. This gets us to a standard state and minimizes @@ -6442,27 +5882,29 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) { last = TREE_PURPOSE (parm); DECL_ARGUMENTS (fndecl) = last; + current_scope->parms = last; + DECL_WEAK (last) = 0; for (parm = TREE_CHAIN (parm); parm; parm = TREE_CHAIN (parm)) if (TREE_PURPOSE (parm)) { TREE_CHAIN (last) = TREE_PURPOSE (parm); last = TREE_PURPOSE (parm); + DECL_WEAK (last) = 0; } + current_scope->parms_last = last; TREE_CHAIN (last) = 0; } - pointer_set_destroy (seen_args); - /* If there was a previous prototype, set the DECL_ARG_TYPE of each argument according to the type previously specified, and report any mismatches. */ - if (current_function_prototype_arg_types) + if (TYPE_ARG_TYPES (TREE_TYPE (fndecl))) { tree type; for (parm = DECL_ARGUMENTS (fndecl), - type = current_function_prototype_arg_types; + type = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); parm || (type && (TYPE_MAIN_VARIANT (TREE_VALUE (type)) != void_type_node)); parm = TREE_CHAIN (parm), type = TREE_CHAIN (type)) @@ -6470,22 +5912,17 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) if (parm == 0 || type == 0 || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) { - if (current_function_prototype_built_in) - warning (0, "number of arguments doesn%'t match " - "built-in prototype"); - else - { - error ("number of arguments doesn%'t match prototype"); - error ("%Hprototype declaration", - ¤t_function_prototype_locus); - } + error ("number of arguments doesn't match prototype"); + error ("%Hprototype declaration", + ¤t_function_prototype_locus); break; } /* Type for passing arg must be consistent with that declared for the arg. ISO C says we take the unqualified type for parameters declared with qualified type. */ - if (!comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)), - TYPE_MAIN_VARIANT (TREE_VALUE (type)))) + if (! comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)), + TYPE_MAIN_VARIANT (TREE_VALUE (type)), + COMPARE_STRICT)) { if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == TYPE_MAIN_VARIANT (TREE_VALUE (type))) @@ -6505,33 +5942,17 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) if (pedantic) { - /* ??? Is it possible to get here with a - built-in prototype or will it always have - been diagnosed as conflicting with an - old-style definition and discarded? */ - if (current_function_prototype_built_in) - warning (0, "promoted argument %qD " - "doesn%'t match built-in prototype", parm); - else - { - pedwarn ("promoted argument %qD " - "doesn%'t match prototype", parm); - pedwarn ("%Hprototype declaration", - ¤t_function_prototype_locus); - } + pedwarn ("promoted argument \"%D\" " + "doesn't match prototype", parm); + pedwarn ("%Hprototype declaration", + ¤t_function_prototype_locus); } } else { - if (current_function_prototype_built_in) - warning (0, "argument %qD doesn%'t match " - "built-in prototype", parm); - else - { - error ("argument %qD doesn%'t match prototype", parm); - error ("%Hprototype declaration", - ¤t_function_prototype_locus); - } + error ("argument \"%D\" doesn't match prototype", parm); + error ("%Hprototype declaration", + ¤t_function_prototype_locus); } } } @@ -6567,22 +5988,12 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) will be a variant of the main variant of the original function type. */ - TREE_TYPE (fndecl) = build_variant_type_copy (TREE_TYPE (fndecl)); + TREE_TYPE (fndecl) = build_type_copy (TREE_TYPE (fndecl)); TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = actual; } } -/* Store parameter declarations passed in ARG_INFO into the current - function declaration. */ - -void -store_parm_decls_from (struct c_arg_info *arg_info) -{ - current_function_arg_info = arg_info; - store_parm_decls (); -} - /* Store the parameter declarations into the current function declaration. This is called after parsing the parameter declarations, before digesting the body of the function. @@ -6594,79 +6005,46 @@ void store_parm_decls (void) { tree fndecl = current_function_decl; - bool proto; - - /* The argument information block for FNDECL. */ - struct c_arg_info *arg_info = current_function_arg_info; - current_function_arg_info = 0; - /* True if this definition is written with a prototype. Note: - despite C99 6.7.5.3p14, we can *not* treat an empty argument - list in a function definition as equivalent to (void) -- an - empty argument list specifies the function has no parameters, - but only (void) sets up a prototype for future calls. */ - proto = arg_info->types != 0; + /* True if this definition is written with a prototype. */ + bool prototype = (current_function_parms + && TREE_CODE (current_function_parms) != TREE_LIST); - if (proto) - store_parm_decls_newstyle (fndecl, arg_info); + if (prototype) + store_parm_decls_newstyle (); else - store_parm_decls_oldstyle (fndecl, arg_info); + store_parm_decls_oldstyle (); - /* The next call to push_scope will be a function body. */ + /* The next call to pushlevel will be a function body. */ next_is_function_body = true; /* Write a record describing this function definition to the prototypes file (if requested). */ - gen_aux_info_record (fndecl, 1, 0, proto); + gen_aux_info_record (fndecl, 1, 0, prototype); /* Initialize the RTL code for the function. */ allocate_struct_function (fndecl); /* Begin the statement tree for this function. */ - DECL_SAVED_TREE (fndecl) = push_stmt_list (); - - /* ??? Insert the contents of the pending sizes list into the function - to be evaluated. The only reason left to have this is - void foo(int n, int array[n++]) - because we throw away the array type in favor of a pointer type, and - thus won't naturally see the SAVE_EXPR containing the increment. All - other pending sizes would be handled by gimplify_parameters. */ - { - tree t; - for (t = nreverse (get_pending_sizes ()); t ; t = TREE_CHAIN (t)) - add_stmt (TREE_VALUE (t)); - } + begin_stmt_tree (&DECL_SAVED_TREE (fndecl)); + + /* Save away the sizes of any variable-size types so that we can + expand them when generating RTL. */ + DECL_LANG_SPECIFIC (fndecl)->pending_sizes = get_pending_sizes (); + + /* This function is being processed in whole-function mode. */ + cfun->x_whole_function_mode_p = 1; /* Even though we're inside a function body, we still don't want to call expand_expr to calculate the size of a variable-sized array. We haven't necessarily assigned RTL to all variables yet, so it's not safe to try to expand expressions involving them. */ + immediate_size_expand = 0; cfun->x_dont_save_pending_sizes_p = 1; } -/* Emit diagnostics that require gimple input for detection. Operate on - FNDECL and all its nested functions. */ - -static void -c_gimple_diagnostics_recursively (tree fndecl) -{ - struct cgraph_node *cgn; - - /* Handle attribute((warn_unused_result)). Relies on gimple input. */ - c_warn_unused_result (&DECL_SAVED_TREE (fndecl)); - - /* Notice when OpenMP structured block constraints are violated. */ - if (flag_openmp) - diagnose_omp_structured_block_errors (fndecl); - - /* Finalize all nested functions now. */ - cgn = cgraph_node (fndecl); - for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) - c_gimple_diagnostics_recursively (cgn->decl); -} - /* Finish up a function declaration and compile that function all the way to assembler language output. The free the storage for the function definition. @@ -6678,20 +6056,33 @@ finish_function (void) { tree fndecl = current_function_decl; - label_context_stack_se = label_context_stack_se->next; - label_context_stack_vm = label_context_stack_vm->next; + /* When a function declaration is totally empty, e.g. + void foo(void) { } + (the argument list is irrelevant) the compstmt rule will not + bother calling pushlevel/poplevel, which means we get here with + the scope stack out of sync. Detect this situation by noticing + that current_scope is still as store_parm_decls left it, and do + a dummy push/pop to get back to consistency. + Note that the call to pushlevel does not actually push another + scope - see there for details. */ + + if (current_scope->parm_flag && next_is_function_body) + { + pushlevel (0); + poplevel (0, 0, 0); + } if (TREE_CODE (fndecl) == FUNCTION_DECL && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))) { tree args = DECL_ARGUMENTS (fndecl); for (; args; args = TREE_CHAIN (args)) - { - tree type = TREE_TYPE (args); - if (INTEGRAL_TYPE_P (type) - && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) - DECL_ARG_TYPE (args) = integer_type_node; - } + { + tree type = TREE_TYPE (args); + if (INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (args) = integer_type_node; + } } if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node) @@ -6710,41 +6101,30 @@ finish_function (void) /* If warn_main is 1 (-Wmain) or 2 (-Wall), we have already warned. If warn_main is -1 (-Wno-main) we don't want to be warned. */ if (!warn_main) - pedwarn ("return type of %q+D is not %<int%>", fndecl); + pedwarn ("%Jreturn type of '%D' is not `int'", fndecl, fndecl); } else { - if (flag_isoc99) - { - tree stmt = c_finish_return (integer_zero_node); -#ifdef USE_MAPPED_LOCATION - /* Hack. We don't want the middle-end to warn that this return - is unreachable, so we mark its location as special. Using - UNKNOWN_LOCATION has the problem that it gets clobbered in - annotate_one_with_locus. A cleaner solution might be to - ensure ! should_carry_locus_p (stmt), but that needs a flag. - */ - SET_EXPR_LOCATION (stmt, BUILTINS_LOCATION); +#ifdef DEFAULT_MAIN_RETURN + /* Make it so that `main' always returns success by default. */ + DEFAULT_MAIN_RETURN; #else - /* Hack. We don't want the middle-end to warn that this - return is unreachable, so put the statement on the - special line 0. */ - annotate_with_file_line (stmt, input_filename, 0); + if (flag_isoc99) + c_expand_return (integer_zero_node); #endif - } } } - /* Tie off the statement tree for this function. */ - DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl)); - finish_fname_decls (); + /* Tie off the statement tree for this function. */ + finish_stmt_tree (&DECL_SAVED_TREE (fndecl)); + /* Complain if there's just no return statement. */ if (warn_return_type && TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE && !current_function_returns_value && !current_function_returns_null - /* Don't complain if we are no-return. */ + /* Don't complain if we abort. */ && !current_function_returns_abnormally /* Don't warn for main(). */ && !MAIN_NAME_P (DECL_NAME (fndecl)) @@ -6753,116 +6133,111 @@ finish_function (void) /* Normally, with -Wreturn-type, flow will complain. Unless we're an inline function, as we might never be compiled separately. */ && DECL_INLINE (fndecl)) - { - warning (OPT_Wreturn_type, - "no return statement in function returning non-void"); - TREE_NO_WARNING (fndecl) = 1; - } + warning ("no return statement in function returning non-void"); /* With just -Wextra, complain only if function returns both with and without a value. */ if (extra_warnings && current_function_returns_value && current_function_returns_null) - warning (OPT_Wextra, "this function may return with or without a value"); - - /* Store the end of the function, so that we get good line number - info for the epilogue. */ - cfun->function_end_locus = input_location; + warning ("this function may return with or without a value"); - /* If we don't have ctors/dtors sections, and this is a static - constructor or destructor, it must be recorded now. */ - if (DECL_STATIC_CONSTRUCTOR (fndecl) - && !targetm.have_ctors_dtors) - static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors); - if (DECL_STATIC_DESTRUCTOR (fndecl) - && !targetm.have_ctors_dtors) - static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors); + /* We're leaving the context of this function, so zap cfun. It's still in + DECL_SAVED_INSNS, and we'll restore it in tree_rest_of_compilation. */ + cfun = NULL; - /* Finalize the ELF visibility for the function. */ - c_determine_visibility (fndecl); + /* ??? Objc emits functions after finalizing the compilation unit. + This should be cleaned up later and this conditional removed. */ + if (!cgraph_global_info_ready) + cgraph_finalize_function (fndecl, false); + else + c_expand_body (fndecl); + current_function_decl = NULL; +} - /* Genericize before inlining. Delay genericizing nested functions - until their parent function is genericized. Since finalizing - requires GENERIC, delay that as well. */ +/* Generate the RTL for a deferred function FNDECL. */ - if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node - && !undef_nested_function) +void +c_expand_deferred_function (tree fndecl) +{ + /* DECL_INLINE or DECL_RESULT might got cleared after the inline + function was deferred, e.g. in duplicate_decls. */ + if (DECL_INLINE (fndecl) && DECL_RESULT (fndecl)) { - if (!decl_function_context (fndecl)) + if (flag_inline_trees) { - c_genericize (fndecl); - c_gimple_diagnostics_recursively (fndecl); + timevar_push (TV_INTEGRATION); + optimize_inline_calls (fndecl); + timevar_pop (TV_INTEGRATION); + } + c_expand_body (fndecl); + current_function_decl = NULL; + } +} - /* ??? Objc emits functions after finalizing the compilation unit. - This should be cleaned up later and this conditional removed. */ - if (cgraph_global_info_ready) - { - c_expand_body (fndecl); - return; - } +/* Generate the RTL for the body of FNDECL. If NESTED_P is nonzero, + then we are already in the process of generating RTL for another + function. */ - cgraph_finalize_function (fndecl, false); - } +static void +c_expand_body_1 (tree fndecl, int nested_p) +{ + if (nested_p) + /* Squirrel away our current state. */ + push_function_context (); + + /* Make sure that we will evaluate variable-sized types involved + in our function's type. */ + put_pending_sizes (DECL_LANG_SPECIFIC (fndecl)->pending_sizes); + tree_rest_of_compilation (fndecl, nested_p); + + if (nested_p) + /* Return to the enclosing function. */ + pop_function_context (); + + if (DECL_STATIC_CONSTRUCTOR (fndecl)) + { + if (targetm.have_ctors_dtors) + (* targetm.asm_out.constructor) (XEXP (DECL_RTL (fndecl), 0), + DEFAULT_INIT_PRIORITY); else - { - /* Register this function with cgraph just far enough to get it - added to our parent's nested function list. Handy, since the - C front end doesn't have such a list. */ - (void) cgraph_node (fndecl); - } + static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors); } - if (!decl_function_context (fndecl)) - undef_nested_function = false; - - /* We're leaving the context of this function, so zap cfun. - It's still in DECL_STRUCT_FUNCTION, and we'll restore it in - tree_rest_of_compilation. */ - cfun = NULL; - current_function_decl = NULL; + if (DECL_STATIC_DESTRUCTOR (fndecl)) + { + if (targetm.have_ctors_dtors) + (* targetm.asm_out.destructor) (XEXP (DECL_RTL (fndecl), 0), + DEFAULT_INIT_PRIORITY); + else + static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors); + } } -/* Generate the RTL for the body of FNDECL. */ +/* Like c_expand_body_1 but only for unnested functions. */ void c_expand_body (tree fndecl) { - if (!DECL_INITIAL (fndecl) - || DECL_INITIAL (fndecl) == error_mark_node) - return; - - tree_rest_of_compilation (fndecl); - - if (DECL_STATIC_CONSTRUCTOR (fndecl) - && targetm.have_ctors_dtors) - targetm.asm_out.constructor (XEXP (DECL_RTL (fndecl), 0), - DEFAULT_INIT_PRIORITY); - if (DECL_STATIC_DESTRUCTOR (fndecl) - && targetm.have_ctors_dtors) - targetm.asm_out.destructor (XEXP (DECL_RTL (fndecl), 0), - DEFAULT_INIT_PRIORITY); + if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node) + c_expand_body_1 (fndecl, 0); } /* Check the declarations given in a for-loop for satisfying the C99 - constraints. If exactly one such decl is found, return it. */ - -tree + constraints. */ +void check_for_loop_decls (void) { - struct c_binding *b; - tree one_decl = NULL_TREE; - int n_decls = 0; - + tree t; if (!flag_isoc99) { /* If we get here, declarations have been used in a for loop without the C99 for loop scope. This doesn't make much sense, so don't allow it. */ - error ("%<for%> loop initial declaration used outside C99 mode"); - return NULL_TREE; + error ("'for' loop initial declaration used outside C99 mode"); + return; } /* C99 subclause 6.8.5 paragraph 3: @@ -6878,47 +6253,36 @@ check_for_loop_decls (void) interpretation, to avoid creating an extension which later causes problems. */ - for (b = current_scope->bindings; b; b = b->prev) + for (t = current_scope->tags; t; t = TREE_CHAIN (t)) { - tree id = b->id; - tree decl = b->decl; + if (TREE_PURPOSE (t) != 0) + { + enum tree_code code = TREE_CODE (TREE_VALUE (t)); - if (!id) - continue; - - switch (TREE_CODE (decl)) - { - case VAR_DECL: - if (TREE_STATIC (decl)) - error ("declaration of static variable %q+D in %<for%> loop " - "initial declaration", decl); - else if (DECL_EXTERNAL (decl)) - error ("declaration of %<extern%> variable %q+D in %<for%> loop " - "initial declaration", decl); - break; - - case RECORD_TYPE: - error ("%<struct %E%> declared in %<for%> loop initial declaration", - id); - break; - case UNION_TYPE: - error ("%<union %E%> declared in %<for%> loop initial declaration", - id); - break; - case ENUMERAL_TYPE: - error ("%<enum %E%> declared in %<for%> loop initial declaration", - id); - break; - default: - error ("declaration of non-variable %q+D in %<for%> loop " - "initial declaration", decl); - } - - n_decls++; - one_decl = decl; + if (code == RECORD_TYPE) + error ("'struct %s' declared in 'for' loop initial declaration", + IDENTIFIER_POINTER (TREE_PURPOSE (t))); + else if (code == UNION_TYPE) + error ("'union %s' declared in 'for' loop initial declaration", + IDENTIFIER_POINTER (TREE_PURPOSE (t))); + else + error ("'enum %s' declared in 'for' loop initial declaration", + IDENTIFIER_POINTER (TREE_PURPOSE (t))); + } } - return n_decls == 1 ? one_decl : NULL_TREE; + for (t = getdecls (); t; t = TREE_CHAIN (t)) + { + if (TREE_CODE (t) != VAR_DECL && DECL_NAME (t)) + error ("%Jdeclaration of non-variable '%D' in 'for' loop " + "initial declaration", t, t); + else if (TREE_STATIC (t)) + error ("%Jdeclaration of static variable '%D' in 'for' loop " + "initial declaration", t, t); + else if (DECL_EXTERNAL (t)) + error ("%Jdeclaration of 'extern' variable '%D' in 'for' loop " + "initial declaration", t, t); + } } /* Save and reinitialize the variables @@ -6928,14 +6292,13 @@ void c_push_function_context (struct function *f) { struct language_function *p; - p = GGC_NEW (struct language_function); + p = ggc_alloc (sizeof (struct language_function)); f->language = p; p->base.x_stmt_tree = c_stmt_tree; - p->x_break_label = c_break_label; - p->x_cont_label = c_cont_label; - p->x_switch_stack = c_switch_stack; - p->arg_info = current_function_arg_info; + p->base.x_scope_stmt_stack = c_scope_stmt_stack; + p->x_in_iteration_stmt = c_in_iteration_stmt; + p->x_in_case_stmt = c_in_case_stmt; p->returns_value = current_function_returns_value; p->returns_null = current_function_returns_null; p->returns_abnormally = current_function_returns_abnormally; @@ -6950,7 +6313,7 @@ c_pop_function_context (struct function *f) { struct language_function *p = f->language; - if (DECL_STRUCT_FUNCTION (current_function_decl) == 0 + if (DECL_SAVED_INSNS (current_function_decl) == 0 && DECL_SAVED_TREE (current_function_decl) == NULL_TREE) { /* Stop pointing to the local nodes about to be freed. */ @@ -6961,10 +6324,9 @@ c_pop_function_context (struct function *f) } c_stmt_tree = p->base.x_stmt_tree; - c_break_label = p->x_break_label; - c_cont_label = p->x_cont_label; - c_switch_stack = p->x_switch_stack; - current_function_arg_info = p->arg_info; + c_scope_stmt_stack = p->base.x_scope_stmt_stack; + c_in_iteration_stmt = p->x_in_iteration_stmt; + c_in_case_stmt = p->x_in_case_stmt; current_function_returns_value = p->returns_value; current_function_returns_null = p->returns_null; current_function_returns_abnormally = p->returns_abnormally; @@ -6984,7 +6346,7 @@ c_dup_lang_specific_decl (tree decl) if (!DECL_LANG_SPECIFIC (decl)) return; - ld = GGC_NEW (struct lang_decl); + ld = ggc_alloc (sizeof (struct lang_decl)); memcpy (ld, DECL_LANG_SPECIFIC (decl), sizeof (struct lang_decl)); DECL_LANG_SPECIFIC (decl) = ld; } @@ -6994,6 +6356,16 @@ c_dup_lang_specific_decl (tree decl) functions are not called from anywhere in the C front end, but as these changes continue, that will change. */ +/* Returns nonzero if the current statement is a full expression, + i.e. temporaries created during that statement should be destroyed + at the end of the statement. */ + +int +stmts_are_full_exprs_p (void) +{ + return 0; +} + /* Returns the stmt_tree (if any) to which statements are currently being added. If there is no active statement-tree, NULL is returned. */ @@ -7004,26 +6376,74 @@ current_stmt_tree (void) return &c_stmt_tree; } +/* Returns the stack of SCOPE_STMTs for the current function. */ + +tree * +current_scope_stmt_stack (void) +{ + return &c_scope_stmt_stack; +} + /* Nonzero if TYPE is an anonymous union or struct type. Always 0 in C. */ int -anon_aggr_type_p (tree ARG_UNUSED (node)) +anon_aggr_type_p (tree node ATTRIBUTE_UNUSED) { return 0; } +/* Dummy function in place of callback used by C++. */ + +void +extract_interface_info (void) +{ +} + +/* Return a new COMPOUND_STMT, after adding it to the current + statement tree. */ + +tree +c_begin_compound_stmt (void) +{ + tree stmt; + + /* Create the COMPOUND_STMT. */ + stmt = add_stmt (build_stmt (COMPOUND_STMT, error_mark_node)); + + return stmt; +} + +/* Expand T (a DECL_STMT) if it declares an entity not handled by the + common code. */ + +void +c_expand_decl_stmt (tree t) +{ + tree decl = DECL_STMT_DECL (t); + + /* Expand nested functions. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_CONTEXT (decl) == current_function_decl + && DECL_SAVED_TREE (decl)) + c_expand_body_1 (decl, 1); +} + /* Return the global value of T as a symbol. */ tree identifier_global_value (tree t) { - struct c_binding *b; + tree decl = IDENTIFIER_SYMBOL_VALUE (t); + if (decl == 0 || DECL_FILE_SCOPE_P (decl)) + return decl; - for (b = I_SYMBOL_BINDING (t); b; b = b->shadowed) - if (B_IN_FILE_SCOPE (b) || B_IN_EXTERNAL_SCOPE (b)) - return b->decl; + /* Shadowed by something else; find the true global value. */ + for (decl = global_scope->names; decl; decl = TREE_CHAIN (decl)) + if (DECL_NAME (decl) == t) + return decl; + /* Only local values for this decl. */ return 0; } @@ -7033,15 +6453,12 @@ identifier_global_value (tree t) void record_builtin_type (enum rid rid_index, const char *name, tree type) { - tree id, decl; + tree id; if (name == 0) id = ridpointers[(int) rid_index]; else id = get_identifier (name); - decl = build_decl (TYPE_DECL, id, type); - pushdecl (decl); - if (debug_hooks->type_decl) - debug_hooks->type_decl (decl, false); + pushdecl (build_decl (TYPE_DECL, id, type)); } /* Build the void_list_node (void_type_node having been created). */ @@ -7052,916 +6469,214 @@ build_void_list_node (void) return t; } -/* Return a c_parm structure with the given SPECS, ATTRS and DECLARATOR. */ - -struct c_parm * -build_c_parm (struct c_declspecs *specs, tree attrs, - struct c_declarator *declarator) -{ - struct c_parm *ret = XOBNEW (&parser_obstack, struct c_parm); - ret->specs = specs; - ret->attrs = attrs; - ret->declarator = declarator; - return ret; -} +/* Return something to represent absolute declarators containing a *. + TARGET is the absolute declarator that the * contains. + TYPE_QUALS_ATTRS is a list of modifiers such as const or volatile + to apply to the pointer type, represented as identifiers, possible mixed + with attributes. -/* Return a declarator with nested attributes. TARGET is the inner - declarator to which these attributes apply. ATTRS are the - attributes. */ + We return an INDIRECT_REF whose "contents" are TARGET (inside a TREE_LIST, + if attributes are present) and whose type is the modifier list. */ -struct c_declarator * -build_attrs_declarator (tree attrs, struct c_declarator *target) +tree +make_pointer_declarator (tree type_quals_attrs, tree target) { - struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); - ret->kind = cdk_attrs; - ret->declarator = target; - ret->u.attrs = attrs; - return ret; + tree quals, attrs; + tree itarget = target; + split_specs_attrs (type_quals_attrs, &quals, &attrs); + if (attrs != NULL_TREE) + itarget = tree_cons (attrs, target, NULL_TREE); + return build1 (INDIRECT_REF, quals, itarget); } -/* Return a declarator for a function with arguments specified by ARGS - and return type specified by TARGET. */ +/* A wrapper around lhd_set_decl_assembler_name that gives static + variables their C names if they are at file scope and only one + translation unit is being compiled, for backwards compatibility + with certain bizarre assembler hacks (like crtstuff.c). */ -struct c_declarator * -build_function_declarator (struct c_arg_info *args, - struct c_declarator *target) +void +c_static_assembler_name (tree decl) { - struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); - ret->kind = cdk_function; - ret->declarator = target; - ret->u.arg_info = args; - return ret; + if (num_in_fnames == 1 + && !TREE_PUBLIC (decl) && DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == TRANSLATION_UNIT_DECL) + SET_DECL_ASSEMBLER_NAME (decl, DECL_NAME (decl)); + else + lhd_set_decl_assembler_name (decl); } -/* Return a declarator for the identifier IDENT (which may be - NULL_TREE for an abstract declarator). */ +/* Hash and equality functions for link_hash_table: key off + DECL_ASSEMBLER_NAME. */ -struct c_declarator * -build_id_declarator (tree ident) +static hashval_t +link_hash_hash (const void *x_p) { - struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); - ret->kind = cdk_id; - ret->declarator = 0; - ret->u.id = ident; - /* Default value - may get reset to a more precise location. */ - ret->id_loc = input_location; - return ret; + tree x = (tree)x_p; + return (hashval_t) (long)DECL_ASSEMBLER_NAME (x); } -/* Return something to represent absolute declarators containing a *. - TARGET is the absolute declarator that the * contains. - TYPE_QUALS_ATTRS is a structure for type qualifiers and attributes - to apply to the pointer type. */ - -struct c_declarator * -make_pointer_declarator (struct c_declspecs *type_quals_attrs, - struct c_declarator *target) +static int +link_hash_eq (const void *x1_p, const void *x2_p) { - tree attrs; - int quals = 0; - struct c_declarator *itarget = target; - struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); - if (type_quals_attrs) - { - attrs = type_quals_attrs->attrs; - quals = quals_from_declspecs (type_quals_attrs); - if (attrs != NULL_TREE) - itarget = build_attrs_declarator (attrs, target); - } - ret->kind = cdk_pointer; - ret->declarator = itarget; - ret->u.pointer_quals = quals; - return ret; + tree x1 = (tree)x1_p; + tree x2 = (tree)x2_p; + return DECL_ASSEMBLER_NAME (x1) == DECL_ASSEMBLER_NAME (x2); } -/* Return a pointer to a structure for an empty list of declaration - specifiers. */ +/* Propagate information between definitions and uses between multiple + translation units in TU_LIST based on linkage rules. */ -struct c_declspecs * -build_null_declspecs (void) +void +merge_translation_unit_decls (void) { - struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs); - ret->type = 0; - ret->decl_attr = 0; - ret->attrs = 0; - ret->typespec_word = cts_none; - ret->storage_class = csc_none; - ret->declspecs_seen_p = false; - ret->type_seen_p = false; - ret->non_sc_seen_p = false; - ret->typedef_p = false; - ret->tag_defined_p = false; - ret->explicit_signed_p = false; - ret->deprecated_p = false; - ret->default_int_p = false; - ret->long_p = false; - ret->long_long_p = false; - ret->short_p = false; - ret->signed_p = false; - ret->unsigned_p = false; - ret->complex_p = false; - ret->inline_p = false; - ret->thread_p = false; - ret->const_p = false; - ret->volatile_p = false; - ret->restrict_p = false; - return ret; -} + const tree tu_list = current_file_decl; + tree tu; + tree decl; + htab_t link_hash_table; + tree block; -/* Add the type qualifier QUAL to the declaration specifiers SPECS, - returning SPECS. */ + /* Create the BLOCK that poplevel would have created, but don't + actually call poplevel since that's expensive. */ + block = make_node (BLOCK); + BLOCK_VARS (block) = current_scope->names; + TREE_USED (block) = 1; + DECL_INITIAL (current_file_decl) = block; -struct c_declspecs * -declspecs_add_qual (struct c_declspecs *specs, tree qual) -{ - enum rid i; - bool dupe = false; - specs->non_sc_seen_p = true; - specs->declspecs_seen_p = true; - gcc_assert (TREE_CODE (qual) == IDENTIFIER_NODE - && C_IS_RESERVED_WORD (qual)); - i = C_RID_CODE (qual); - switch (i) - { - case RID_CONST: - dupe = specs->const_p; - specs->const_p = true; - break; - case RID_VOLATILE: - dupe = specs->volatile_p; - specs->volatile_p = true; - break; - case RID_RESTRICT: - dupe = specs->restrict_p; - specs->restrict_p = true; - break; - default: - gcc_unreachable (); - } - if (dupe && pedantic && !flag_isoc99) - pedwarn ("duplicate %qE", qual); - return specs; -} + /* If only one translation unit seen, no copying necessary. */ + if (TREE_CHAIN (tu_list) == NULL_TREE) + return; -/* Add the type specifier TYPE to the declaration specifiers SPECS, - returning SPECS. */ + link_hash_table = htab_create (1021, link_hash_hash, link_hash_eq, NULL); -struct c_declspecs * -declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) -{ - tree type = spec.spec; - specs->non_sc_seen_p = true; - specs->declspecs_seen_p = true; - specs->type_seen_p = true; - if (TREE_DEPRECATED (type)) - specs->deprecated_p = true; - - /* Handle type specifier keywords. */ - if (TREE_CODE (type) == IDENTIFIER_NODE && C_IS_RESERVED_WORD (type)) - { - enum rid i = C_RID_CODE (type); - if (specs->type) - { - error ("two or more data types in declaration specifiers"); - return specs; - } - if ((int) i <= (int) RID_LAST_MODIFIER) + /* Enter any actual definitions into the hash table. */ + for (tu = tu_list; tu; tu = TREE_CHAIN (tu)) + for (decl = BLOCK_VARS (DECL_INITIAL (tu)); decl; decl = TREE_CHAIN (decl)) + if (TREE_PUBLIC (decl) && ! DECL_EXTERNAL (decl)) { - /* "long", "short", "signed", "unsigned" or "_Complex". */ - bool dupe = false; - switch (i) + PTR *slot; + slot = htab_find_slot (link_hash_table, decl, INSERT); + + /* If we've already got a definition, work out which one is + the real one, put it into the hash table, and make the + other one DECL_EXTERNAL. This is important to avoid + putting out two definitions of the same symbol in the + assembly output. */ + if (*slot != NULL) { - case RID_LONG: - if (specs->long_long_p) + tree old_decl = (tree) *slot; + + /* If this is weak or common or whatever, suppress it + in favor of the other definition. */ + if (DECL_WEAK (decl)) + DECL_EXTERNAL (decl) = 1; + else if (DECL_WEAK (old_decl) && ! DECL_WEAK (decl)) + DECL_EXTERNAL (old_decl) = 1; + else if (DECL_COMMON (decl) || DECL_ONE_ONLY (decl)) + DECL_EXTERNAL (decl) = 1; + else if (DECL_COMMON (old_decl) || DECL_ONE_ONLY (old_decl)) + DECL_EXTERNAL (old_decl) = 1; + + if (DECL_EXTERNAL (decl)) { - error ("%<long long long%> is too long for GCC"); - break; + DECL_INITIAL (decl) = NULL_TREE; + DECL_COMMON (decl) = 0; + DECL_ONE_ONLY (decl) = 0; + DECL_WEAK (decl) = 0; } - if (specs->long_p) + else if (DECL_EXTERNAL (old_decl)) { - if (specs->typespec_word == cts_double) - { - error ("both %<long long%> and %<double%> in " - "declaration specifiers"); - break; - } - if (pedantic && !flag_isoc99 && !in_system_header - && warn_long_long) - pedwarn ("ISO C90 does not support %<long long%>"); - specs->long_long_p = 1; - break; + DECL_INITIAL (old_decl) = NULL_TREE; + DECL_COMMON (old_decl) = 0; + DECL_ONE_ONLY (old_decl) = 0; + DECL_WEAK (old_decl) = 0; + *slot = decl; } - if (specs->short_p) - error ("both %<long%> and %<short%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_void) - error ("both %<long%> and %<void%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_bool) - error ("both %<long%> and %<_Bool%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_char) - error ("both %<long%> and %<char%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_float) - error ("both %<long%> and %<float%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat32) - error ("both %<long%> and %<_Decimal32%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat64) - error ("both %<long%> and %<_Decimal64%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat128) - error ("both %<long%> and %<_Decimal128%> in " - "declaration specifiers"); else - specs->long_p = true; - break; - case RID_SHORT: - dupe = specs->short_p; - if (specs->long_p) - error ("both %<long%> and %<short%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_void) - error ("both %<short%> and %<void%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_bool) - error ("both %<short%> and %<_Bool%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_char) - error ("both %<short%> and %<char%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_float) - error ("both %<short%> and %<float%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_double) - error ("both %<short%> and %<double%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat32) - error ("both %<short%> and %<_Decimal32%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat64) - error ("both %<short%> and %<_Decimal64%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat128) - error ("both %<short%> and %<_Decimal128%> in " - "declaration specifiers"); - else - specs->short_p = true; - break; - case RID_SIGNED: - dupe = specs->signed_p; - if (specs->unsigned_p) - error ("both %<signed%> and %<unsigned%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_void) - error ("both %<signed%> and %<void%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_bool) - error ("both %<signed%> and %<_Bool%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_float) - error ("both %<signed%> and %<float%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_double) - error ("both %<signed%> and %<double%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat32) - error ("both %<signed%> and %<_Decimal32%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat64) - error ("both %<signed%> and %<_Decimal64%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat128) - error ("both %<signed%> and %<_Decimal128%> in " - "declaration specifiers"); - else - specs->signed_p = true; - break; - case RID_UNSIGNED: - dupe = specs->unsigned_p; - if (specs->signed_p) - error ("both %<signed%> and %<unsigned%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_void) - error ("both %<unsigned%> and %<void%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_bool) - error ("both %<unsigned%> and %<_Bool%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_float) - error ("both %<unsigned%> and %<float%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_double) - error ("both %<unsigned%> and %<double%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat32) - error ("both %<unsigned%> and %<_Decimal32%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat64) - error ("both %<unsigned%> and %<_Decimal64%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat128) - error ("both %<unsigned%> and %<_Decimal128%> in " - "declaration specifiers"); - else - specs->unsigned_p = true; - break; - case RID_COMPLEX: - dupe = specs->complex_p; - if (pedantic && !flag_isoc99 && !in_system_header) - pedwarn ("ISO C90 does not support complex types"); - if (specs->typespec_word == cts_void) - error ("both %<complex%> and %<void%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_bool) - error ("both %<complex%> and %<_Bool%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat32) - error ("both %<complex%> and %<_Decimal32%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat64) - error ("both %<complex%> and %<_Decimal64%> in " - "declaration specifiers"); - else if (specs->typespec_word == cts_dfloat128) - error ("both %<complex%> and %<_Decimal128%> in " - "declaration specifiers"); - else - specs->complex_p = true; - break; - default: - gcc_unreachable (); - } - - if (dupe) - error ("duplicate %qE", type); - - return specs; - } - else - { - /* "void", "_Bool", "char", "int", "float" or "double". */ - if (specs->typespec_word != cts_none) - { - error ("two or more data types in declaration specifiers"); - return specs; - } - switch (i) - { - case RID_VOID: - if (specs->long_p) - error ("both %<long%> and %<void%> in " - "declaration specifiers"); - else if (specs->short_p) - error ("both %<short%> and %<void%> in " - "declaration specifiers"); - else if (specs->signed_p) - error ("both %<signed%> and %<void%> in " - "declaration specifiers"); - else if (specs->unsigned_p) - error ("both %<unsigned%> and %<void%> in " - "declaration specifiers"); - else if (specs->complex_p) - error ("both %<complex%> and %<void%> in " - "declaration specifiers"); - else - specs->typespec_word = cts_void; - return specs; - case RID_BOOL: - if (specs->long_p) - error ("both %<long%> and %<_Bool%> in " - "declaration specifiers"); - else if (specs->short_p) - error ("both %<short%> and %<_Bool%> in " - "declaration specifiers"); - else if (specs->signed_p) - error ("both %<signed%> and %<_Bool%> in " - "declaration specifiers"); - else if (specs->unsigned_p) - error ("both %<unsigned%> and %<_Bool%> in " - "declaration specifiers"); - else if (specs->complex_p) - error ("both %<complex%> and %<_Bool%> in " - "declaration specifiers"); - else - specs->typespec_word = cts_bool; - return specs; - case RID_CHAR: - if (specs->long_p) - error ("both %<long%> and %<char%> in " - "declaration specifiers"); - else if (specs->short_p) - error ("both %<short%> and %<char%> in " - "declaration specifiers"); - else - specs->typespec_word = cts_char; - return specs; - case RID_INT: - specs->typespec_word = cts_int; - return specs; - case RID_FLOAT: - if (specs->long_p) - error ("both %<long%> and %<float%> in " - "declaration specifiers"); - else if (specs->short_p) - error ("both %<short%> and %<float%> in " - "declaration specifiers"); - else if (specs->signed_p) - error ("both %<signed%> and %<float%> in " - "declaration specifiers"); - else if (specs->unsigned_p) - error ("both %<unsigned%> and %<float%> in " - "declaration specifiers"); - else - specs->typespec_word = cts_float; - return specs; - case RID_DOUBLE: - if (specs->long_long_p) - error ("both %<long long%> and %<double%> in " - "declaration specifiers"); - else if (specs->short_p) - error ("both %<short%> and %<double%> in " - "declaration specifiers"); - else if (specs->signed_p) - error ("both %<signed%> and %<double%> in " - "declaration specifiers"); - else if (specs->unsigned_p) - error ("both %<unsigned%> and %<double%> in " - "declaration specifiers"); - else - specs->typespec_word = cts_double; - return specs; - case RID_DFLOAT32: - case RID_DFLOAT64: - case RID_DFLOAT128: - { - const char *str; - if (i == RID_DFLOAT32) - str = "_Decimal32"; - else if (i == RID_DFLOAT64) - str = "_Decimal64"; - else - str = "_Decimal128"; - if (specs->long_long_p) - error ("both %<long long%> and %<%s%> in " - "declaration specifiers", str); - if (specs->long_p) - error ("both %<long%> and %<%s%> in " - "declaration specifiers", str); - else if (specs->short_p) - error ("both %<short%> and %<%s%> in " - "declaration specifiers", str); - else if (specs->signed_p) - error ("both %<signed%> and %<%s%> in " - "declaration specifiers", str); - else if (specs->unsigned_p) - error ("both %<unsigned%> and %<%s%> in " - "declaration specifiers", str); - else if (specs->complex_p) - error ("both %<complex%> and %<%s%> in " - "declaration specifiers", str); - else if (i == RID_DFLOAT32) - specs->typespec_word = cts_dfloat32; - else if (i == RID_DFLOAT64) - specs->typespec_word = cts_dfloat64; - else - specs->typespec_word = cts_dfloat128; - } - if (!targetm.decimal_float_supported_p ()) - error ("decimal floating point not supported for this target"); - if (pedantic) - pedwarn ("ISO C does not support decimal floating point"); - return specs; - default: - /* ObjC reserved word "id", handled below. */ - break; + { + error ("%Jredefinition of global '%D'", decl, decl); + error ("%J'%D' previously defined here", old_decl, old_decl); + } } + else + *slot = decl; } - } - /* Now we have a typedef (a TYPE_DECL node), an identifier (some - form of ObjC type, cases such as "int" and "long" being handled - above), a TYPE (struct, union, enum and typeof specifiers) or an - ERROR_MARK. In none of these cases may there have previously - been any type specifiers. */ - if (specs->type || specs->typespec_word != cts_none - || specs->long_p || specs->short_p || specs->signed_p - || specs->unsigned_p || specs->complex_p) - error ("two or more data types in declaration specifiers"); - else if (TREE_CODE (type) == TYPE_DECL) - { - if (TREE_TYPE (type) == error_mark_node) - ; /* Allow the type to default to int to avoid cascading errors. */ - else + /* Now insert the desired information from all the definitions + into any plain declarations. */ + for (tu = tu_list; tu; tu = TREE_CHAIN (tu)) + for (decl = BLOCK_VARS (DECL_INITIAL (tu)); decl; decl = TREE_CHAIN (decl)) + if (TREE_PUBLIC (decl) && DECL_EXTERNAL (decl)) { - specs->type = TREE_TYPE (type); - specs->decl_attr = DECL_ATTRIBUTES (type); - specs->typedef_p = true; - specs->explicit_signed_p = C_TYPEDEF_EXPLICITLY_SIGNED (type); - } - } - else if (TREE_CODE (type) == IDENTIFIER_NODE) - { - tree t = lookup_name (type); - if (!t || TREE_CODE (t) != TYPE_DECL) - error ("%qE fails to be a typedef or built in type", type); - else if (TREE_TYPE (t) == error_mark_node) - ; - else - specs->type = TREE_TYPE (t); - } - else if (TREE_CODE (type) != ERROR_MARK) - { - if (spec.kind == ctsk_tagdef || spec.kind == ctsk_tagfirstref) - specs->tag_defined_p = true; - if (spec.kind == ctsk_typeof) - specs->typedef_p = true; - specs->type = type; - } - - return specs; -} + tree global_decl; + global_decl = htab_find (link_hash_table, decl); -/* Add the storage class specifier or function specifier SCSPEC to the - declaration specifiers SPECS, returning SPECS. */ + if (! global_decl) + continue; -struct c_declspecs * -declspecs_add_scspec (struct c_declspecs *specs, tree scspec) -{ - enum rid i; - enum c_storage_class n = csc_none; - bool dupe = false; - specs->declspecs_seen_p = true; - gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE - && C_IS_RESERVED_WORD (scspec)); - i = C_RID_CODE (scspec); - if (extra_warnings && specs->non_sc_seen_p) - warning (OPT_Wextra, "%qE is not at beginning of declaration", scspec); - switch (i) - { - case RID_INLINE: - /* C99 permits duplicate inline. Although of doubtful utility, - it seems simplest to permit it in gnu89 mode as well, as - there is also little utility in maintaining this as a - difference between gnu89 and C99 inline. */ - dupe = false; - specs->inline_p = true; - break; - case RID_THREAD: - dupe = specs->thread_p; - if (specs->storage_class == csc_auto) - error ("%<__thread%> used with %<auto%>"); - else if (specs->storage_class == csc_register) - error ("%<__thread%> used with %<register%>"); - else if (specs->storage_class == csc_typedef) - error ("%<__thread%> used with %<typedef%>"); - else - specs->thread_p = true; - break; - case RID_AUTO: - n = csc_auto; - break; - case RID_EXTERN: - n = csc_extern; - /* Diagnose "__thread extern". */ - if (specs->thread_p) - error ("%<__thread%> before %<extern%>"); - break; - case RID_REGISTER: - n = csc_register; - break; - case RID_STATIC: - n = csc_static; - /* Diagnose "__thread static". */ - if (specs->thread_p) - error ("%<__thread%> before %<static%>"); - break; - case RID_TYPEDEF: - n = csc_typedef; - break; - default: - gcc_unreachable (); - } - if (n != csc_none && n == specs->storage_class) - dupe = true; - if (dupe) - error ("duplicate %qE", scspec); - if (n != csc_none) - { - if (specs->storage_class != csc_none && n != specs->storage_class) - { - error ("multiple storage classes in declaration specifiers"); + /* Print any appropriate error messages, and partially merge + the decls. */ + (void) duplicate_decls (decl, global_decl); } - else - { - specs->storage_class = n; - if (n != csc_extern && n != csc_static && specs->thread_p) - { - error ("%<__thread%> used with %qE", scspec); - specs->thread_p = false; - } - } - } - return specs; -} - -/* Add the attributes ATTRS to the declaration specifiers SPECS, - returning SPECS. */ -struct c_declspecs * -declspecs_add_attrs (struct c_declspecs *specs, tree attrs) -{ - specs->attrs = chainon (attrs, specs->attrs); - specs->declspecs_seen_p = true; - return specs; + htab_delete (link_hash_table); } -/* Combine "long", "short", "signed", "unsigned" and "_Complex" type - specifiers with any other type specifier to determine the resulting - type. This is where ISO C checks on complex types are made, since - "_Complex long" is a prefix of the valid ISO C type "_Complex long - double". */ +/* Perform final processing on file-scope data. */ -struct c_declspecs * -finish_declspecs (struct c_declspecs *specs) +void +c_write_global_declarations(void) { - /* If a type was specified as a whole, we have no modifiers and are - done. */ - if (specs->type != NULL_TREE) - { - gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p - && !specs->complex_p); - return specs; - } - - /* If none of "void", "_Bool", "char", "int", "float" or "double" - has been specified, treat it as "int" unless "_Complex" is - present and there are no other specifiers. If we just have - "_Complex", it is equivalent to "_Complex double", but e.g. - "_Complex short" is equivalent to "_Complex short int". */ - if (specs->typespec_word == cts_none) - { - if (specs->long_p || specs->short_p - || specs->signed_p || specs->unsigned_p) - { - specs->typespec_word = cts_int; - } - else if (specs->complex_p) - { - specs->typespec_word = cts_double; - if (pedantic) - pedwarn ("ISO C does not support plain %<complex%> meaning " - "%<double complex%>"); - } - else - { - specs->typespec_word = cts_int; - specs->default_int_p = true; - /* We don't diagnose this here because grokdeclarator will - give more specific diagnostics according to whether it is - a function definition. */ - } - } + tree link; - /* If "signed" was specified, record this to distinguish "int" and - "signed int" in the case of a bit-field with - -funsigned-bitfields. */ - specs->explicit_signed_p = specs->signed_p; - - /* Now compute the actual type. */ - switch (specs->typespec_word) + for (link = current_file_decl; link; link = TREE_CHAIN (link)) { - case cts_void: - gcc_assert (!specs->long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p - && !specs->complex_p); - specs->type = void_type_node; - break; - case cts_bool: - gcc_assert (!specs->long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p - && !specs->complex_p); - specs->type = boolean_type_node; - break; - case cts_char: - gcc_assert (!specs->long_p && !specs->short_p); - gcc_assert (!(specs->signed_p && specs->unsigned_p)); - if (specs->signed_p) - specs->type = signed_char_type_node; - else if (specs->unsigned_p) - specs->type = unsigned_char_type_node; - else - specs->type = char_type_node; - if (specs->complex_p) - { - if (pedantic) - pedwarn ("ISO C does not support complex integer types"); - specs->type = build_complex_type (specs->type); - } - break; - case cts_int: - gcc_assert (!(specs->long_p && specs->short_p)); - gcc_assert (!(specs->signed_p && specs->unsigned_p)); - if (specs->long_long_p) - specs->type = (specs->unsigned_p - ? long_long_unsigned_type_node - : long_long_integer_type_node); - else if (specs->long_p) - specs->type = (specs->unsigned_p - ? long_unsigned_type_node - : long_integer_type_node); - else if (specs->short_p) - specs->type = (specs->unsigned_p - ? short_unsigned_type_node - : short_integer_type_node); - else - specs->type = (specs->unsigned_p - ? unsigned_type_node - : integer_type_node); - if (specs->complex_p) - { - if (pedantic) - pedwarn ("ISO C does not support complex integer types"); - specs->type = build_complex_type (specs->type); - } - break; - case cts_float: - gcc_assert (!specs->long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p); - specs->type = (specs->complex_p - ? complex_float_type_node - : float_type_node); - break; - case cts_double: - gcc_assert (!specs->long_long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p); - if (specs->long_p) - { - specs->type = (specs->complex_p - ? complex_long_double_type_node - : long_double_type_node); - } - else - { - specs->type = (specs->complex_p - ? complex_double_type_node - : double_type_node); - } - break; - case cts_dfloat32: - case cts_dfloat64: - case cts_dfloat128: - gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p - && !specs->signed_p && !specs->unsigned_p && !specs->complex_p); - if (specs->typespec_word == cts_dfloat32) - specs->type = dfloat32_type_node; - else if (specs->typespec_word == cts_dfloat64) - specs->type = dfloat64_type_node; - else - specs->type = dfloat128_type_node; - break; - default: - gcc_unreachable (); - } - - return specs; -} - -/* Synthesize a function which calls all the global ctors or global - dtors in this file. This is only used for targets which do not - support .ctors/.dtors sections. FIXME: Migrate into cgraph. */ -static void -build_cdtor (int method_type, tree cdtors) -{ - tree body = 0; + tree globals = BLOCK_VARS (DECL_INITIAL (link)); + int len = list_length (globals); + tree *vec = xmalloc (sizeof (tree) * len); + int i; + tree decl; - if (!cdtors) - return; + /* Process the decls in the order they were written. */ - for (; cdtors; cdtors = TREE_CHAIN (cdtors)) - append_to_statement_list (build_function_call (TREE_VALUE (cdtors), 0), - &body); + for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl)) + vec[i] = decl; - cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY); -} + wrapup_global_declarations (vec, len); -/* A subroutine of c_write_global_declarations. Perform final processing - on one file scope's declarations (or the external scope's declarations), - GLOBALS. */ + check_global_declarations (vec, len); -static void -c_write_global_declarations_1 (tree globals) -{ - tree decl; - bool reconsider; - - /* Process the decls in the order they were written. */ - for (decl = globals; decl; decl = TREE_CHAIN (decl)) - { - /* Check for used but undefined static functions using the C - standard's definition of "used", and set TREE_NO_WARNING so - that check_global_declarations doesn't repeat the check. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_INITIAL (decl) == 0 - && DECL_EXTERNAL (decl) - && !TREE_PUBLIC (decl) - && C_DECL_USED (decl)) - { - pedwarn ("%q+F used but never defined", decl); - TREE_NO_WARNING (decl) = 1; - } - - wrapup_global_declaration_1 (decl); + /* Clean up. */ + free (vec); } - - do - { - reconsider = false; - for (decl = globals; decl; decl = TREE_CHAIN (decl)) - reconsider |= wrapup_global_declaration_2 (decl); - } - while (reconsider); - - for (decl = globals; decl; decl = TREE_CHAIN (decl)) - check_global_declaration_1 (decl); -} - -/* A subroutine of c_write_global_declarations Emit debug information for each - of the declarations in GLOBALS. */ - -static void -c_write_global_declarations_2 (tree globals) -{ - tree decl; - - for (decl = globals; decl ; decl = TREE_CHAIN (decl)) - debug_hooks->global_decl (decl); } -/* Preserve the external declarations scope across a garbage collect. */ -static GTY(()) tree ext_block; +/* Reset the parser's state in preparation for a new file. */ void -c_write_global_declarations (void) +c_reset_state (void) { - tree t; - - /* We don't want to do this if generating a PCH. */ - if (pch_file) - return; - - /* Don't waste time on further processing if -fsyntax-only or we've - encountered errors. */ - if (flag_syntax_only || errorcount || sorrycount || cpp_errors (parse_in)) - return; - - /* Close the external scope. */ - ext_block = pop_scope (); - external_scope = 0; - gcc_assert (!current_scope); - - if (ext_block) - { - tree tmp = BLOCK_VARS (ext_block); - int flags; - FILE * stream = dump_begin (TDI_tu, &flags); - if (stream && tmp) - { - dump_node (tmp, flags & ~TDF_SLIM, stream); - dump_end (TDI_tu, stream); - } - } - - /* Process all file scopes in this compilation, and the external_scope, - through wrapup_global_declarations and check_global_declarations. */ - for (t = all_translation_units; t; t = TREE_CHAIN (t)) - c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t))); - c_write_global_declarations_1 (BLOCK_VARS (ext_block)); - - /* Generate functions to call static constructors and destructors - for targets that do not support .ctors/.dtors sections. These - functions have magic names which are detected by collect2. */ - build_cdtor ('I', static_ctors); static_ctors = 0; - build_cdtor ('D', static_dtors); static_dtors = 0; - - /* We're done parsing; proceed to optimize and emit assembly. - FIXME: shouldn't be the front end's responsibility to call this. */ - cgraph_optimize (); - - /* After cgraph has had a chance to emit everything that's going to - be emitted, output debug information for globals. */ - if (errorcount == 0 && sorrycount == 0) - { - timevar_push (TV_SYMOUT); - for (t = all_translation_units; t; t = TREE_CHAIN (t)) - c_write_global_declarations_2 (BLOCK_VARS (DECL_INITIAL (t))); - c_write_global_declarations_2 (BLOCK_VARS (ext_block)); - timevar_pop (TV_SYMOUT); - } - - ext_block = NULL; + tree link; + tree file_scope_decl; + + /* Pop the global scope. */ + if (current_scope != global_scope) + current_scope = global_scope; + file_scope_decl = current_file_decl; + DECL_INITIAL (file_scope_decl) = poplevel (1, 0, 0); + BLOCK_SUPERCONTEXT (DECL_INITIAL (file_scope_decl)) = file_scope_decl; + truly_local_externals = NULL_TREE; + + /* Start a new global binding level. */ + pushlevel (0); + global_scope = current_scope; + current_file_decl = build_decl (TRANSLATION_UNIT_DECL, NULL, NULL); + TREE_CHAIN (current_file_decl) = file_scope_decl; + + /* Reintroduce the builtin declarations. */ + for (link = first_builtin_decl; + link != TREE_CHAIN (last_builtin_decl); + link = TREE_CHAIN (link)) + pushdecl (copy_node (link)); } #include "gt-c-decl.h" diff --git a/contrib/gcc/c-format.c b/contrib/gcc/c-format.c index 403724e..34327a9 100644 --- a/contrib/gcc/c-format.c +++ b/contrib/gcc/c-format.c @@ -1,6 +1,6 @@ /* Check calls to formatted I/O functions (-Wformat). Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,10 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* $FreeBSD$ */ #include "config.h" #include "system.h" @@ -25,12 +27,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "tm.h" #include "tree.h" #include "flags.h" -#include "c-common.h" #include "toplev.h" +#include "c-common.h" #include "intl.h" #include "diagnostic.h" #include "langhooks.h" -#include "c-format.h" /* Set format warning options according to a -Wformat=n option. */ @@ -54,25 +55,24 @@ set_Wformat (int setting) /* Handle attributes associated with format checking. */ -/* This must be in the same order as format_types, except for - format_type_error. Target-specific format types do not have - matching enum values. */ +/* This must be in the same order as format_types, with format_type_error + last. */ enum format_type { printf_format_type, asm_fprintf_format_type, - gcc_diag_format_type, gcc_tdiag_format_type, - gcc_cdiag_format_type, - gcc_cxxdiag_format_type, gcc_gfc_format_type, + gcc_diag_format_type, gcc_cdiag_format_type, + gcc_cxxdiag_format_type, scanf_format_type, strftime_format_type, - strfmon_format_type, format_type_error = -1}; + strfmon_format_type, rintf0_format_type, + format_type_error }; typedef struct function_format_info { - int format_type; /* type of format (printf, scanf, etc.) */ + enum format_type format_type; /* type of format (printf, scanf, etc.) */ unsigned HOST_WIDE_INT format_num; /* number of format argument */ unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */ } function_format_info; static bool decode_format_attr (tree, function_format_info *, int); -static int decode_format_type (const char *); +static enum format_type decode_format_type (const char *); static bool check_format_string (tree argument, unsigned HOST_WIDE_INT format_num, @@ -84,12 +84,12 @@ static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value, /* Handle a "format_arg" attribute; arguments as in struct attribute_spec.handler. */ tree -handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name), +handle_format_arg_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args, int flags, bool *no_add_attrs) { tree type = *node; tree format_num_expr = TREE_VALUE (args); - unsigned HOST_WIDE_INT format_num = 0; + unsigned HOST_WIDE_INT format_num; tree argument; if (!get_constant (format_num_expr, &format_num, 0)) @@ -140,7 +140,7 @@ check_format_string (tree argument, unsigned HOST_WIDE_INT format_num, != char_type_node)) { if (!(flags & (int) ATTR_FLAG_BUILT_IN)) - error ("format string argument not a string type"); + error ("format string arg not a string type"); *no_add_attrs = true; return false; } @@ -148,15 +148,21 @@ check_format_string (tree argument, unsigned HOST_WIDE_INT format_num, return true; } -/* Verify EXPR is a constant, and store its value. - If validated_p is true there should be no errors. +/* Strip any conversions from the expression, verify it is a constant, + and store its value. If validated_p is true, abort on errors. Returns true on success, false otherwise. */ static bool -get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p) +get_constant(tree expr, unsigned HOST_WIDE_INT *value, int validated_p) { + while (TREE_CODE (expr) == NOP_EXPR + || TREE_CODE (expr) == CONVERT_EXPR + || TREE_CODE (expr) == NON_LVALUE_EXPR) + expr = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) != INTEGER_CST || TREE_INT_CST_HIGH (expr) != 0) { - gcc_assert (!validated_p); + if (validated_p) + abort (); return false; } @@ -165,12 +171,12 @@ get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p) return true; } -/* Decode the arguments to a "format" attribute into a - function_format_info structure. It is already known that the list - is of the right length. If VALIDATED_P is true, then these - attributes have already been validated and must not be erroneous; - if false, it will give an error message. Returns true if the - attributes are successfully decoded, false otherwise. */ +/* Decode the arguments to a "format" attribute into a function_format_info + structure. It is already known that the list is of the right length. + If VALIDATED_P is true, then these attributes have already been validated + and this function will abort if they are erroneous; if false, it + will give an error message. Returns true if the attributes are + successfully decoded, false otherwise. */ static bool decode_format_attr (tree args, function_format_info *info, int validated_p) @@ -182,8 +188,9 @@ decode_format_attr (tree args, function_format_info *info, int validated_p) if (TREE_CODE (format_type_id) != IDENTIFIER_NODE) { - gcc_assert (!validated_p); - error ("unrecognized format specifier"); + if (validated_p) + abort (); + error("%Junrecognized format specifier", getdecls()); return false; } else @@ -194,9 +201,9 @@ decode_format_attr (tree args, function_format_info *info, int validated_p) if (info->format_type == format_type_error) { - gcc_assert (!validated_p); - warning (OPT_Wformat, "%qE is an unrecognized format function type", - format_type_id); + if (validated_p) + abort (); + warning ("`%s' is an unrecognized format function type", p); return false; } } @@ -209,14 +216,15 @@ decode_format_attr (tree args, function_format_info *info, int validated_p) if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p)) { - error ("%<...%> has invalid operand number"); + error ("'...' has invalid operand number"); return false; } if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num) { - gcc_assert (!validated_p); - error ("format string argument follows the args to be formatted"); + if (validated_p) + abort (); + error ("format string arg follows the args to be formatted"); return false; } @@ -225,14 +233,41 @@ decode_format_attr (tree args, function_format_info *info, int validated_p) /* Check a call to a format function against a parameter list. */ +/* The meaningfully distinct length modifiers for format checking recognized + by GCC. */ +enum format_lengths +{ + FMT_LEN_none, + FMT_LEN_hh, + FMT_LEN_h, + FMT_LEN_l, + FMT_LEN_ll, + FMT_LEN_L, + FMT_LEN_z, + FMT_LEN_t, + FMT_LEN_j, + FMT_LEN_MAX +}; + + +/* The standard versions in which various format features appeared. */ +enum format_std_version +{ + STD_C89, + STD_C94, + STD_C9L, /* C99, but treat as C89 if -Wno-long-long. */ + STD_C99, + STD_EXT +}; + /* The C standard version C++ is treated as equivalent to or inheriting from, for the purpose of format features supported. */ #define CPLUSPLUS_STD_VER STD_C94 /* The C standard version we are checking formats against when pedantic. */ -#define C_STD_VER ((int) (c_dialect_cxx () \ - ? CPLUSPLUS_STD_VER \ - : (flag_isoc99 \ - ? STD_C99 \ +#define C_STD_VER ((int)(c_dialect_cxx () \ + ? CPLUSPLUS_STD_VER \ + : (flag_isoc99 \ + ? STD_C99 \ : (flag_isoc94 ? STD_C94 : STD_C89)))) /* The name to give to the standard version we are warning about when pedantic. FEATURE_VER is the version in which the feature warned out @@ -244,10 +279,200 @@ decode_format_attr (tree args, function_format_info *info, int validated_p) : "ISO C90")) /* Adjust a C standard version, which may be STD_C9L, to account for -Wno-long-long. Returns other standard versions unchanged. */ -#define ADJ_STD(VER) ((int) ((VER) == STD_C9L \ +#define ADJ_STD(VER) ((int)((VER) == STD_C9L \ ? (warn_long_long ? STD_C99 : STD_C89) \ : (VER))) +/* Flags that may apply to a particular kind of format checked by GCC. */ +enum +{ + /* This format converts arguments of types determined by the + format string. */ + FMT_FLAG_ARG_CONVERT = 1, + /* The scanf allocation 'a' kludge applies to this format kind. */ + FMT_FLAG_SCANF_A_KLUDGE = 2, + /* A % during parsing a specifier is allowed to be a modified % rather + that indicating the format is broken and we are out-of-sync. */ + FMT_FLAG_FANCY_PERCENT_OK = 4, + /* With $ operand numbers, it is OK to reference the same argument more + than once. */ + FMT_FLAG_DOLLAR_MULTIPLE = 8, + /* This format type uses $ operand numbers (strfmon doesn't). */ + FMT_FLAG_USE_DOLLAR = 16, + /* Zero width is bad in this type of format (scanf). */ + FMT_FLAG_ZERO_WIDTH_BAD = 32, + /* Empty precision specification is OK in this type of format (printf). */ + FMT_FLAG_EMPTY_PREC_OK = 64, + /* Gaps are allowed in the arguments with $ operand numbers if all + arguments are pointers (scanf). */ + FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128 + /* Not included here: details of whether width or precision may occur + (controlled by width_char and precision_char); details of whether + '*' can be used for these (width_type and precision_type); details + of whether length modifiers can occur (length_char_specs). */ +}; + + +/* Structure describing a length modifier supported in format checking, and + possibly a doubled version such as "hh". */ +typedef struct +{ + /* Name of the single-character length modifier. */ + const char *name; + /* Index into a format_char_info.types array. */ + enum format_lengths index; + /* Standard version this length appears in. */ + enum format_std_version std; + /* Same, if the modifier can be repeated, or NULL if it can't. */ + const char *double_name; + enum format_lengths double_index; + enum format_std_version double_std; +} format_length_info; + + +/* Structure describing the combination of a conversion specifier + (or a set of specifiers which act identically) and a length modifier. */ +typedef struct +{ + /* The standard version this combination of length and type appeared in. + This is only relevant if greater than those for length and type + individually; otherwise it is ignored. */ + enum format_std_version std; + /* The name to use for the type, if different from that generated internally + (e.g., "signed size_t"). */ + const char *name; + /* The type itself. */ + tree *type; +} format_type_detail; + + +/* Macros to fill out tables of these. */ +#define NOARGUMENTS { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } +#define BADLEN { 0, NULL, NULL } +#define NOLENGTHS { BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } + + +/* Structure describing a format conversion specifier (or a set of specifiers + which act identically), and the length modifiers used with it. */ +typedef struct +{ + const char *format_chars; + int pointer_count; + enum format_std_version std; + /* Types accepted for each length modifier. */ + format_type_detail types[FMT_LEN_MAX]; + /* List of other modifier characters allowed with these specifiers. + This lists flags, and additionally "w" for width, "p" for precision + (right precision, for strfmon), "#" for left precision (strfmon), + "a" for scanf "a" allocation extension (not applicable in C99 mode), + "*" for scanf suppression, and "E" and "O" for those strftime + modifiers. */ + const char *flag_chars; + /* List of additional flags describing these conversion specifiers. + "c" for generic character pointers being allowed, "2" for strftime + two digit year formats, "3" for strftime formats giving two digit + years in some locales, "4" for "2" which becomes "3" with an "E" modifier, + "o" if use of strftime "O" is a GNU extension beyond C99, + "W" if the argument is a pointer which is dereferenced and written into, + "R" if the argument is a pointer which is dereferenced and read from, + "i" for printf integer formats where the '0' flag is ignored with + precision, and "[" for the starting character of a scanf scanset. */ + const char *flags2; +} format_char_info; + + +/* Structure describing a flag accepted by some kind of format. */ +typedef struct +{ + /* The flag character in question (0 for end of array). */ + int flag_char; + /* Zero if this entry describes the flag character in general, or a + nonzero character that may be found in flags2 if it describes the + flag when used with certain formats only. If the latter, only + the first such entry found that applies to the current conversion + specifier is used; the values of `name' and `long_name' it supplies + will be used, if non-NULL and the standard version is higher than + the unpredicated one, for any pedantic warning. For example, 'o' + for strftime formats (meaning 'O' is an extension over C99). */ + int predicate; + /* Nonzero if the next character after this flag in the format should + be skipped ('=' in strfmon), zero otherwise. */ + int skip_next_char; + /* The name to use for this flag in diagnostic messages. For example, + N_("`0' flag"), N_("field width"). */ + const char *name; + /* Long name for this flag in diagnostic messages; currently only used for + "ISO C does not support ...". For example, N_("the `I' printf flag"). */ + const char *long_name; + /* The standard version in which it appeared. */ + enum format_std_version std; +} format_flag_spec; + + +/* Structure describing a combination of flags that is bad for some kind + of format. */ +typedef struct +{ + /* The first flag character in question (0 for end of array). */ + int flag_char1; + /* The second flag character. */ + int flag_char2; + /* Nonzero if the message should say that the first flag is ignored with + the second, zero if the combination should simply be objected to. */ + int ignored; + /* Zero if this entry applies whenever this flag combination occurs, + a nonzero character from flags2 if it only applies in some + circumstances (e.g. 'i' for printf formats ignoring 0 with precision). */ + int predicate; +} format_flag_pair; + + +/* Structure describing a particular kind of format processed by GCC. */ +typedef struct +{ + /* The name of this kind of format, for use in diagnostics. Also + the name of the attribute (without preceding and following __). */ + const char *name; + /* Specifications of the length modifiers accepted; possibly NULL. */ + const format_length_info *length_char_specs; + /* Details of the conversion specification characters accepted. */ + const format_char_info *conversion_specs; + /* String listing the flag characters that are accepted. */ + const char *flag_chars; + /* String listing modifier characters (strftime) accepted. May be NULL. */ + const char *modifier_chars; + /* Details of the flag characters, including pseudo-flags. */ + const format_flag_spec *flag_specs; + /* Details of bad combinations of flags. */ + const format_flag_pair *bad_flag_pairs; + /* Flags applicable to this kind of format. */ + int flags; + /* Flag character to treat a width as, or 0 if width not used. */ + int width_char; + /* Flag character to treat a left precision (strfmon) as, + or 0 if left precision not used. */ + int left_precision_char; + /* Flag character to treat a precision (for strfmon, right precision) as, + or 0 if precision not used. */ + int precision_char; + /* If a flag character has the effect of suppressing the conversion of + an argument ('*' in scanf), that flag character, otherwise 0. */ + int suppression_char; + /* Flag character to treat a length modifier as (ignored if length + modifiers not used). Need not be placed in flag_chars for conversion + specifiers, but is used to check for bad combinations such as length + modifier with assignment suppression in scanf. */ + int length_code_char; + /* Pointer to type of argument expected if '*' is used for a width, + or NULL if '*' not used for widths. */ + tree *width_type; + /* Pointer to type of argument expected if '*' is used for a precision, + or NULL if '*' not used for precisions. */ + tree *precision_type; + const int null_format_ok; +} format_kind_info; + + /* Structure describing details of a type expected in format checking, and the type to check against it. */ typedef struct format_wanted_type @@ -267,10 +492,12 @@ typedef struct format_wanted_type /* Whether the argument, dereferenced once, is read from and so must not be a NULL pointer. */ int reading_from_flag; - /* If warnings should be of the form "field precision should have - type 'int'", the name to use (in this case "field precision"), - otherwise NULL, for "format expects type 'long'" type - messages. */ + /* If warnings should be of the form "field precision is not type int", + the name to use (in this case "field precision"), otherwise NULL, + for "%s format, %s arg" type messages. If (in an extension), this + is a pointer type, wanted_type_name should be set to include the + terminating '*' characters of the type name to give a correct + message. */ const char *name; /* The actual parameter to check against the wanted type. */ tree param; @@ -291,8 +518,6 @@ static const format_length_info printf_length_specs[] = { "Z", FMT_LEN_z, STD_EXT, NULL, 0, 0 }, { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 }, { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 }, - { "H", FMT_LEN_H, STD_EXT, NULL, 0, 0 }, - { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT }, { NULL, 0, 0, NULL, 0, 0 } }; @@ -313,7 +538,6 @@ static const format_length_info gcc_diag_length_specs[] = }; /* The custom diagnostics all accept the same length specifiers. */ -#define gcc_tdiag_length_specs gcc_diag_length_specs #define gcc_cdiag_length_specs gcc_diag_length_specs #define gcc_cxxdiag_length_specs gcc_diag_length_specs @@ -327,8 +551,6 @@ static const format_length_info scanf_length_specs[] = { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 }, { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 }, { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 }, - { "H", FMT_LEN_H, STD_EXT, NULL, 0, 0 }, - { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT }, { NULL, 0, 0, NULL, 0, 0 } }; @@ -344,13 +566,13 @@ static const format_length_info strfmon_length_specs[] = static const format_flag_spec printf_flag_specs[] = { - { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 }, - { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, - { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, - { '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 }, - { '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 }, - { '\'', 0, 0, N_("''' flag"), N_("the ''' printf flag"), STD_EXT }, - { 'I', 0, 0, N_("'I' flag"), N_("the 'I' printf flag"), STD_EXT }, + { ' ', 0, 0, N_("` ' flag"), N_("the ` ' printf flag"), STD_C89 }, + { '+', 0, 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 }, + { '#', 0, 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 }, + { '0', 0, 0, N_("`0' flag"), N_("the `0' printf flag"), STD_C89 }, + { '-', 0, 0, N_("`-' flag"), N_("the `-' printf flag"), STD_C89 }, + { '\'', 0, 0, N_("`'' flag"), N_("the `'' printf flag"), STD_EXT }, + { 'I', 0, 0, N_("`I' flag"), N_("the `I' printf flag"), STD_EXT }, { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, @@ -368,11 +590,11 @@ static const format_flag_pair printf_flag_pairs[] = static const format_flag_spec asm_fprintf_flag_specs[] = { - { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 }, - { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, - { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, - { '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 }, - { '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 }, + { ' ', 0, 0, N_("` ' flag"), N_("the ` ' printf flag"), STD_C89 }, + { '+', 0, 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 }, + { '#', 0, 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 }, + { '0', 0, 0, N_("`0' flag"), N_("the `0' printf flag"), STD_C89 }, + { '-', 0, 0, N_("`-' flag"), N_("the `-' printf flag"), STD_C89 }, { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, @@ -392,32 +614,22 @@ static const format_flag_pair gcc_diag_flag_pairs[] = { 0, 0, 0, 0 } }; -#define gcc_tdiag_flag_pairs gcc_diag_flag_pairs #define gcc_cdiag_flag_pairs gcc_diag_flag_pairs #define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs -static const format_flag_pair gcc_gfc_flag_pairs[] = -{ - { 0, 0, 0, 0 } -}; - static const format_flag_spec gcc_diag_flag_specs[] = { - { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, - { 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 }, { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, { 0, 0, 0, NULL, NULL, 0 } }; -#define gcc_tdiag_flag_specs gcc_diag_flag_specs #define gcc_cdiag_flag_specs gcc_diag_flag_specs static const format_flag_spec gcc_cxxdiag_flag_specs[] = { - { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, - { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, - { 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 }, + { '+', 0, 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 }, + { '#', 0, 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 }, { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, { 0, 0, 0, NULL, NULL, 0 } @@ -426,11 +638,11 @@ static const format_flag_spec gcc_cxxdiag_flag_specs[] = static const format_flag_spec scanf_flag_specs[] = { { '*', 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 }, - { 'a', 0, 0, N_("'a' flag"), N_("the 'a' scanf flag"), STD_EXT }, + { 'a', 0, 0, N_("`a' flag"), N_("the `a' scanf flag"), STD_EXT }, { 'w', 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 }, { 'L', 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 }, - { '\'', 0, 0, N_("''' flag"), N_("the ''' scanf flag"), STD_EXT }, - { 'I', 0, 0, N_("'I' flag"), N_("the 'I' scanf flag"), STD_EXT }, + { '\'', 0, 0, N_("`'' flag"), N_("the `'' scanf flag"), STD_EXT }, + { 'I', 0, 0, N_("`I' flag"), N_("the `I' scanf flag"), STD_EXT }, { 0, 0, 0, NULL, NULL, 0 } }; @@ -444,15 +656,15 @@ static const format_flag_pair scanf_flag_pairs[] = static const format_flag_spec strftime_flag_specs[] = { - { '_', 0, 0, N_("'_' flag"), N_("the '_' strftime flag"), STD_EXT }, - { '-', 0, 0, N_("'-' flag"), N_("the '-' strftime flag"), STD_EXT }, - { '0', 0, 0, N_("'0' flag"), N_("the '0' strftime flag"), STD_EXT }, - { '^', 0, 0, N_("'^' flag"), N_("the '^' strftime flag"), STD_EXT }, - { '#', 0, 0, N_("'#' flag"), N_("the '#' strftime flag"), STD_EXT }, + { '_', 0, 0, N_("`_' flag"), N_("the `_' strftime flag"), STD_EXT }, + { '-', 0, 0, N_("`-' flag"), N_("the `-' strftime flag"), STD_EXT }, + { '0', 0, 0, N_("`0' flag"), N_("the `0' strftime flag"), STD_EXT }, + { '^', 0, 0, N_("`^' flag"), N_("the `^' strftime flag"), STD_EXT }, + { '#', 0, 0, N_("`#' flag"), N_("the `#' strftime flag"), STD_EXT }, { 'w', 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT }, - { 'E', 0, 0, N_("'E' modifier"), N_("the 'E' strftime modifier"), STD_C99 }, - { 'O', 0, 0, N_("'O' modifier"), N_("the 'O' strftime modifier"), STD_C99 }, - { 'O', 'o', 0, NULL, N_("the 'O' modifier"), STD_EXT }, + { 'E', 0, 0, N_("`E' modifier"), N_("the `E' strftime modifier"), STD_C99 }, + { 'O', 0, 0, N_("`O' modifier"), N_("the `O' strftime modifier"), STD_C99 }, + { 'O', 'o', 0, NULL, N_("the `O' modifier"), STD_EXT }, { 0, 0, 0, NULL, NULL, 0 } }; @@ -471,11 +683,11 @@ static const format_flag_pair strftime_flag_pairs[] = static const format_flag_spec strfmon_flag_specs[] = { { '=', 0, 1, N_("fill character"), N_("fill character in strfmon format"), STD_C89 }, - { '^', 0, 0, N_("'^' flag"), N_("the '^' strfmon flag"), STD_C89 }, - { '+', 0, 0, N_("'+' flag"), N_("the '+' strfmon flag"), STD_C89 }, - { '(', 0, 0, N_("'(' flag"), N_("the '(' strfmon flag"), STD_C89 }, - { '!', 0, 0, N_("'!' flag"), N_("the '!' strfmon flag"), STD_C89 }, - { '-', 0, 0, N_("'-' flag"), N_("the '-' strfmon flag"), STD_C89 }, + { '^', 0, 0, N_("`^' flag"), N_("the `^' strfmon flag"), STD_C89 }, + { '+', 0, 0, N_("`+' flag"), N_("the `+' strfmon flag"), STD_C89 }, + { '(', 0, 0, N_("`(' flag"), N_("the `(' strfmon flag"), STD_C89 }, + { '!', 0, 0, N_("`!' flag"), N_("the `!' strfmon flag"), STD_C89 }, + { '-', 0, 0, N_("`-' flag"), N_("the `-' strfmon flag"), STD_C89 }, { 'w', 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 }, { '#', 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 }, { 'p', 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 }, @@ -490,275 +702,292 @@ static const format_flag_pair strfmon_flag_pairs[] = }; +#define T_I &integer_type_node +#define T89_I { STD_C89, NULL, T_I } +#define T_L &long_integer_type_node +#define T89_L { STD_C89, NULL, T_L } +#define T_LL &long_long_integer_type_node +#define T9L_LL { STD_C9L, NULL, T_LL } +#define TEX_LL { STD_EXT, NULL, T_LL } +#define T_S &short_integer_type_node +#define T89_S { STD_C89, NULL, T_S } +#define T_UI &unsigned_type_node +#define T89_UI { STD_C89, NULL, T_UI } +#define T_UL &long_unsigned_type_node +#define T89_UL { STD_C89, NULL, T_UL } +#define T_ULL &long_long_unsigned_type_node +#define T9L_ULL { STD_C9L, NULL, T_ULL } +#define TEX_ULL { STD_EXT, NULL, T_ULL } +#define T_US &short_unsigned_type_node +#define T89_US { STD_C89, NULL, T_US } +#define T_F &float_type_node +#define T89_F { STD_C89, NULL, T_F } +#define T99_F { STD_C99, NULL, T_F } +#define T_D &double_type_node +#define T89_D { STD_C89, NULL, T_D } +#define T99_D { STD_C99, NULL, T_D } +#define T_LD &long_double_type_node +#define T89_LD { STD_C89, NULL, T_LD } +#define T99_LD { STD_C99, NULL, T_LD } +#define T_C &char_type_node +#define T89_C { STD_C89, NULL, T_C } +#define T_SC &signed_char_type_node +#define T99_SC { STD_C99, NULL, T_SC } +#define T_UC &unsigned_char_type_node +#define T99_UC { STD_C99, NULL, T_UC } +#define T_V &void_type_node +#define T89_V { STD_C89, NULL, T_V } +#define T_W &wchar_type_node +#define T94_W { STD_C94, "wchar_t", T_W } +#define TEX_W { STD_EXT, "wchar_t", T_W } +#define T_WI &wint_type_node +#define T94_WI { STD_C94, "wint_t", T_WI } +#define TEX_WI { STD_EXT, "wint_t", T_WI } +#define T_ST &size_type_node +#define T99_ST { STD_C99, "size_t", T_ST } +#define T_SST &signed_size_type_node +#define T99_SST { STD_C99, "signed size_t", T_SST } +#define T_PD &ptrdiff_type_node +#define T99_PD { STD_C99, "ptrdiff_t", T_PD } +#define T_UPD &unsigned_ptrdiff_type_node +#define T99_UPD { STD_C99, "unsigned ptrdiff_t", T_UPD } +#define T_IM &intmax_type_node +#define T99_IM { STD_C99, "intmax_t", T_IM } +#define T_UIM &uintmax_type_node +#define T99_UIM { STD_C99, "uintmax_t", T_UIM } + static const format_char_info print_char_table[] = { /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "-wp0 +'I", "i", NULL }, - { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL }, - { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0'I", "i", NULL }, - { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL }, - { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#I", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c", NULL }, - { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "", "W", NULL }, + { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "-wp0 +'I", "i" }, + { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0#", "i" }, + { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0'I", "i" }, + { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "" }, + { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#I", "" }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR" }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c" }, + { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W" }, /* C99 conversion specifiers. */ - { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL }, - { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL }, + { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "" }, + { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "" }, /* X/Open conversion specifiers. */ - { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, - { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL }, + { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, + { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R" }, /* GNU conversion specifiers. */ - { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "" }, + /* BSD conversion specifiers. */ + /* FreeBSD kernel extensions (src/sys/kern/subr_prf.c). + The format %b is supported to decode error registers. + Its usage is: printf("reg=%b\n", regval, "<base><arg>*"); + which produces: reg=3<BITTWO,BITONE> + The format %D provides a hexdump given a pointer and separator string: + ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX + ("%*D", len, ptr, " ") -> XX XX XX XX ... + */ + { "D", 1, STD_EXT, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR" }, + { "b", 1, STD_EXT, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "" }, + { "ry", 0, STD_EXT, { T89_I, BADLEN, BADLEN, T89_L, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "i" }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL } }; static const format_char_info asm_fprintf_char_table[] = { /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +", "i", NULL }, - { "oxX", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0", "i", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +", "i" }, + { "oxX", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i" }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0", "i" }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR" }, /* asm_fprintf conversion specifiers. */ - { "O", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "R", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "I", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "L", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "U", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, - { "@", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { "O", 0, STD_C89, NOARGUMENTS, "", "" }, + { "R", 0, STD_C89, NOARGUMENTS, "", "" }, + { "I", 0, STD_C89, NOARGUMENTS, "", "" }, + { "L", 0, STD_C89, NOARGUMENTS, "", "" }, + { "U", 0, STD_C89, NOARGUMENTS, "", "" }, + { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "@", 0, STD_C89, NOARGUMENTS, "", "" }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL } }; static const format_char_info gcc_diag_char_table[] = { /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "p", "cR" }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "c" }, /* Custom conversion specifiers. */ /* %H will require "location_t" at runtime. */ - { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, /* These will require a "tree" at runtime. */ - { "J", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "J", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, - { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info gcc_tdiag_char_table[] = -{ - /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, - - /* Custom conversion specifiers. */ - - /* %H will require "location_t" at runtime. */ - { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - - /* These will require a "tree" at runtime. */ - { "DFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, - - { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { "m", 0, STD_C89, NOARGUMENTS, "", "" }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL } }; static const format_char_info gcc_cdiag_char_table[] = { /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "p", "cR" }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "c" }, /* Custom conversion specifiers. */ /* %H will require "location_t" at runtime. */ - { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, /* These will require a "tree" at runtime. */ - { "DEFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, + { "DEFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, - { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { "m", 0, STD_C89, NOARGUMENTS, "", "" }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL } }; static const format_char_info gcc_cxxdiag_char_table[] = { /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "p", "cR" }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "c" }, /* Custom conversion specifiers. */ /* %H will require "location_t" at runtime. */ - { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, /* These will require a "tree" at runtime. */ - { "ADEFJTV",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL }, - - /* These accept either an 'int' or an 'enum tree_code' (which is handled as an 'int'.) */ - { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - - { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } -}; - -static const format_char_info gcc_gfc_char_table[] = -{ - /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL }, + { "ADEFJTV",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "+#", "" }, - /* gfc conversion specifiers. */ + /* These accept either an `int' or an `enum tree_code' (which is handled as an `int'.) */ + { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, - { "C", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - - /* This will require a "locus" at runtime. */ - { "L", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "R", NULL }, - - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { "m", 0, STD_C89, NOARGUMENTS, "", "" }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL } }; static const format_char_info scan_char_table[] = { /* C89 conversion specifiers. */ - { "di", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "*w'I", "W", NULL }, - { "u", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "*w'I", "W", NULL }, - { "oxX", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, - { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "*w'", "W", NULL }, - { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "cW", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW", NULL }, - { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW[", NULL }, - { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, - { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "", "W", NULL }, + { "di", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "*w'I", "W" }, + { "u", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "*w'I", "W" }, + { "oxX", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "*w", "W" }, + { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W" }, + { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "cW" }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW" }, + { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW[" }, + { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W" }, + { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W" }, /* C99 conversion specifiers. */ - { "F", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "*w'", "W", NULL }, - { "aA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, + { "FaA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W" }, /* X/Open conversion specifiers. */ - { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, - { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "W", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W" }, + { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "W" }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL } }; static const format_char_info time_char_table[] = { /* C89 conversion specifiers. */ - { "ABZab", 0, STD_C89, NOLENGTHS, "^#", "", NULL }, - { "cx", 0, STD_C89, NOLENGTHS, "E", "3", NULL }, - { "HIMSUWdmw", 0, STD_C89, NOLENGTHS, "-_0Ow", "", NULL }, - { "j", 0, STD_C89, NOLENGTHS, "-_0Ow", "o", NULL }, - { "p", 0, STD_C89, NOLENGTHS, "#", "", NULL }, - { "X", 0, STD_C89, NOLENGTHS, "E", "", NULL }, - { "y", 0, STD_C89, NOLENGTHS, "EO-_0w", "4", NULL }, - { "Y", 0, STD_C89, NOLENGTHS, "-_0EOw", "o", NULL }, - { "%", 0, STD_C89, NOLENGTHS, "", "", NULL }, + { "ABZab", 0, STD_C89, NOLENGTHS, "^#", "" }, + { "cx", 0, STD_C89, NOLENGTHS, "E", "3" }, + { "HIMSUWdmw", 0, STD_C89, NOLENGTHS, "-_0Ow", "" }, + { "j", 0, STD_C89, NOLENGTHS, "-_0Ow", "o" }, + { "p", 0, STD_C89, NOLENGTHS, "#", "" }, + { "X", 0, STD_C89, NOLENGTHS, "E", "" }, + { "y", 0, STD_C89, NOLENGTHS, "EO-_0w", "4" }, + { "Y", 0, STD_C89, NOLENGTHS, "-_0EOw", "o" }, + { "%", 0, STD_C89, NOLENGTHS, "", "" }, /* C99 conversion specifiers. */ - { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o", NULL }, - { "D", 0, STD_C99, NOLENGTHS, "", "2", NULL }, - { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "", NULL }, - { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "", NULL }, - { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o", NULL }, - { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o", NULL }, - { "h", 0, STD_C99, NOLENGTHS, "^#", "", NULL }, - { "z", 0, STD_C99, NOLENGTHS, "O", "o", NULL }, + { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o" }, + { "D", 0, STD_C99, NOLENGTHS, "", "2" }, + { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "" }, + { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "" }, + { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o" }, + { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o" }, + { "h", 0, STD_C99, NOLENGTHS, "^#", "" }, + { "z", 0, STD_C99, NOLENGTHS, "O", "o" }, /* GNU conversion specifiers. */ - { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "", NULL }, - { "P", 0, STD_EXT, NOLENGTHS, "", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "" }, + { "P", 0, STD_EXT, NOLENGTHS, "", "" }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL } }; static const format_char_info monetary_char_table[] = { - { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "" }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL } }; + /* This must be in the same order as enum format_type. */ static const format_kind_info format_types_orig[] = { - { "printf", printf_length_specs, print_char_table, " +#0-'I", NULL, + { "printf", printf_length_specs, print_char_table, " +#0-'I", NULL, printf_flag_specs, printf_flag_pairs, FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK, 'w', 0, 'p', 0, 'L', - &integer_type_node, &integer_type_node + &integer_type_node, &integer_type_node, 0 }, - { "asm_fprintf", asm_fprintf_length_specs, asm_fprintf_char_table, " +#0-", NULL, + { "asm_fprintf", asm_fprintf_length_specs, asm_fprintf_char_table, " +#0-", NULL, asm_fprintf_flag_specs, asm_fprintf_flag_pairs, FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK, 'w', 0, 'p', 0, 'L', NULL, NULL }, - { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "q+", NULL, + { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "", NULL, gcc_diag_flag_specs, gcc_diag_flag_pairs, FMT_FLAG_ARG_CONVERT, 0, 0, 'p', 0, 'L', NULL, &integer_type_node }, - { "gcc_tdiag", gcc_tdiag_length_specs, gcc_tdiag_char_table, "q+", NULL, - gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs, - FMT_FLAG_ARG_CONVERT, - 0, 0, 'p', 0, 'L', - NULL, &integer_type_node - }, - { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "q+", NULL, + { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "", NULL, gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs, FMT_FLAG_ARG_CONVERT, 0, 0, 'p', 0, 'L', NULL, &integer_type_node }, - { "gcc_cxxdiag", gcc_cxxdiag_length_specs, gcc_cxxdiag_char_table, "q+#", NULL, + { "gcc_cxxdiag", gcc_cxxdiag_length_specs, gcc_cxxdiag_char_table, "+#", NULL, gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs, FMT_FLAG_ARG_CONVERT, 0, 0, 'p', 0, 'L', NULL, &integer_type_node }, - { "gcc_gfc", NULL, gcc_gfc_char_table, "", NULL, - NULL, gcc_gfc_flag_pairs, - FMT_FLAG_ARG_CONVERT, - 0, 0, 0, 0, 0, - NULL, NULL - }, - { "scanf", scanf_length_specs, scan_char_table, "*'I", NULL, + { "scanf", scanf_length_specs, scan_char_table, "*'I", NULL, scanf_flag_specs, scanf_flag_pairs, FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK, 'w', 0, 0, '*', 'L', - NULL, NULL + NULL, NULL, 0 }, { "strftime", NULL, time_char_table, "_-0^#", "EO", strftime_flag_specs, strftime_flag_pairs, FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, - NULL, NULL + NULL, NULL, 0 }, - { "strfmon", strfmon_length_specs, monetary_char_table, "=^+(!-", NULL, + { "strfmon", strfmon_length_specs, monetary_char_table, "=^+(!-", NULL, strfmon_flag_specs, strfmon_flag_pairs, FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', - NULL, NULL + NULL, NULL, 0 + }, + { "printf0", printf_length_specs, print_char_table, " +#0-'I", NULL, + printf_flag_specs, printf_flag_pairs, + FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK, + 'w', 0, 'p', 0, 'L', + &integer_type_node, &integer_type_node, 1 } }; @@ -766,12 +995,9 @@ static const format_kind_info format_types_orig[] = new data if necessary, while still allowing the original data to be const. */ static const format_kind_info *format_types = format_types_orig; -/* We can modify this one. We also add target-specific format types - to the end of the array. */ +/* We can modify this one. */ static format_kind_info *dynamic_format_types; -static int n_format_types = ARRAY_SIZE (format_types_orig); - /* Structure detailing the results of checking a format function call where the format expression may be a conditional expression with many leaves resulting from nested conditional expressions. */ @@ -804,49 +1030,49 @@ typedef struct format_check_results *res; function_format_info *info; tree params; + int *status; } format_check_context; -static void check_format_info (function_format_info *, tree); +static void check_format_info (int *, function_format_info *, tree); static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT); -static void check_format_info_main (format_check_results *, +static void check_format_info_main (int *, format_check_results *, function_format_info *, const char *, int, tree, unsigned HOST_WIDE_INT); +static void status_warning (int *, const char *, ...) + ATTRIBUTE_PRINTF_2; static void init_dollar_format_checking (int, tree); -static int maybe_read_dollar_number (const char **, int, +static int maybe_read_dollar_number (int *, const char **, int, tree, tree *, const format_kind_info *); -static bool avoid_dollar_number (const char *); -static void finish_dollar_format_checking (format_check_results *, int); +static void finish_dollar_format_checking (int *, format_check_results *, int); static const format_flag_spec *get_flag_spec (const format_flag_spec *, int, const char *); -static void check_format_types (format_wanted_type *, const char *, int); -static void format_type_warning (const char *, const char *, int, tree, - int, const char *, tree, int); +static void check_format_types (int *, format_wanted_type *); /* Decode a format type from a string, returning the type, or format_type_error if not valid, in which case the caller should print an error message. */ -static int +static enum format_type decode_format_type (const char *s) { int i; int slen; slen = strlen (s); - for (i = 0; i < n_format_types; i++) + for (i = 0; i < (int) format_type_error; i++) { int alen; if (!strcmp (s, format_types[i].name)) - return i; + break; alen = strlen (format_types[i].name); if (slen == alen + 4 && s[0] == '_' && s[1] == '_' && s[slen - 1] == '_' && s[slen - 2] == '_' && !strncmp (s + 2, format_types[i].name, alen)) - return i; + break; } - return format_type_error; + return ((enum format_type) i); } @@ -857,7 +1083,7 @@ decode_format_type (const char *s) attribute themselves. */ void -check_function_format (tree attrs, tree params) +check_function_format (int *status, tree attrs, tree params) { tree a; @@ -869,8 +1095,7 @@ check_function_format (tree attrs, tree params) /* Yup; check it. */ function_format_info info; decode_format_attr (TREE_VALUE (a), &info, 1); - if (warn_format) - check_format_info (&info, params); + check_format_info (status, &info, params); if (warn_missing_format_attribute && info.first_arg_num == 0 && (format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT)) @@ -901,8 +1126,7 @@ check_function_format (tree attrs, tree params) break; } if (args != 0) - warning (OPT_Wmissing_format_attribute, "function might " - "be possible candidate for %qs format attribute", + warning ("function might be possible candidate for `%s' format attribute", format_types[info.format_type].name); } } @@ -910,6 +1134,31 @@ check_function_format (tree attrs, tree params) } } +/* This function replaces `warning' inside the printf format checking + functions. If the `status' parameter is non-NULL, then it is + dereferenced and set to 1 whenever a warning is caught. Otherwise + it warns as usual by replicating the innards of the warning + function from diagnostic.c. */ +static void +status_warning (int *status, const char *msgid, ...) +{ + diagnostic_info diagnostic ; + va_list ap; + + va_start (ap, msgid); + + if (status) + *status = 1; + else + { + /* This duplicates the warning function behavior. */ + diagnostic_set_info (&diagnostic, _(msgid), &ap, + input_location, DK_WARNING); + report_diagnostic (&diagnostic); + } + + va_end (ap); +} /* Variables used by the checking of $ operand number formats. */ static char *dollar_arguments_used = NULL; @@ -950,8 +1199,8 @@ init_dollar_format_checking (int first_arg_num, tree params) if (dollar_arguments_pointer_p) free (dollar_arguments_pointer_p); dollar_arguments_alloc = dollar_arguments_count; - dollar_arguments_used = XNEWVEC (char, dollar_arguments_alloc); - dollar_arguments_pointer_p = XNEWVEC (char, dollar_arguments_alloc); + dollar_arguments_used = xmalloc (dollar_arguments_alloc); + dollar_arguments_pointer_p = xmalloc (dollar_arguments_alloc); } if (dollar_arguments_alloc) { @@ -982,18 +1231,18 @@ init_dollar_format_checking (int first_arg_num, tree params) a $ format is found, *FORMAT is updated to point just after it. */ static int -maybe_read_dollar_number (const char **format, +maybe_read_dollar_number (int *status, const char **format, int dollar_needed, tree params, tree *param_ptr, const format_kind_info *fki) { int argnum; int overflow_flag; const char *fcp = *format; - if (!ISDIGIT (*fcp)) + if (! ISDIGIT (*fcp)) { if (dollar_needed) { - warning (OPT_Wformat, "missing $ operand number in format"); + status_warning (status, "missing $ operand number in format"); return -1; } else @@ -1014,7 +1263,7 @@ maybe_read_dollar_number (const char **format, { if (dollar_needed) { - warning (OPT_Wformat, "missing $ operand number in format"); + status_warning (status, "missing $ operand number in format"); return -1; } else @@ -1023,14 +1272,15 @@ maybe_read_dollar_number (const char **format, *format = fcp + 1; if (pedantic && !dollar_format_warned) { - warning (OPT_Wformat, "%s does not support %%n$ operand number formats", - C_STD_NAME (STD_EXT)); + status_warning (status, + "%s does not support %%n$ operand number formats", + C_STD_NAME (STD_EXT)); dollar_format_warned = 1; } if (overflow_flag || argnum == 0 || (dollar_first_arg_num && argnum > dollar_arguments_count)) { - warning (OPT_Wformat, "operand number out of range in format"); + status_warning (status, "operand number out of range in format"); return -1; } if (argnum > dollar_max_arg_used) @@ -1041,10 +1291,9 @@ maybe_read_dollar_number (const char **format, { int nalloc; nalloc = 2 * dollar_arguments_alloc + 16; - dollar_arguments_used = XRESIZEVEC (char, dollar_arguments_used, - nalloc); - dollar_arguments_pointer_p = XRESIZEVEC (char, dollar_arguments_pointer_p, - nalloc); + dollar_arguments_used = xrealloc (dollar_arguments_used, nalloc); + dollar_arguments_pointer_p = xrealloc (dollar_arguments_pointer_p, + nalloc); memset (dollar_arguments_used + dollar_arguments_alloc, 0, nalloc - dollar_arguments_alloc); dollar_arguments_alloc = nalloc; @@ -1053,8 +1302,9 @@ maybe_read_dollar_number (const char **format, && dollar_arguments_used[argnum - 1] == 1) { dollar_arguments_used[argnum - 1] = 2; - warning (OPT_Wformat, "format argument %d used more than once in %s format", - argnum, fki->name); + status_warning (status, + "format argument %d used more than once in %s format", + argnum, fki->name); } else dollar_arguments_used[argnum - 1] = 1; @@ -1065,32 +1315,17 @@ maybe_read_dollar_number (const char **format, for (i = 1; i < argnum && *param_ptr != 0; i++) *param_ptr = TREE_CHAIN (*param_ptr); - /* This case shouldn't be caught here. */ - gcc_assert (*param_ptr); + if (*param_ptr == 0) + { + /* This case shouldn't be caught here. */ + abort (); + } } else *param_ptr = 0; return argnum; } -/* Ensure that FORMAT does not start with a decimal number followed by - a $; give a diagnostic and return true if it does, false otherwise. */ - -static bool -avoid_dollar_number (const char *format) -{ - if (!ISDIGIT (*format)) - return false; - while (ISDIGIT (*format)) - format++; - if (*format == '$') - { - warning (OPT_Wformat, "$ operand number used after format without operand number"); - return true; - } - return false; -} - /* Finish the checking for a format string that used $ operand number formats instead of non-$ formats. We check for unused operands before used ones @@ -1103,7 +1338,7 @@ avoid_dollar_number (const char *format) pointers. */ static void -finish_dollar_format_checking (format_check_results *res, int pointer_gap_ok) +finish_dollar_format_checking (int *status, format_check_results *res, int pointer_gap_ok) { int i; bool found_pointer_gap = false; @@ -1115,9 +1350,8 @@ finish_dollar_format_checking (format_check_results *res, int pointer_gap_ok) || dollar_arguments_pointer_p[i])) found_pointer_gap = true; else - warning (OPT_Wformat, - "format argument %d unused before used argument %d in $-style format", - i + 1, dollar_max_arg_used); + status_warning (status, "format argument %d unused before used argument %d in $-style format", + i + 1, dollar_max_arg_used); } } if (found_pointer_gap @@ -1133,10 +1367,10 @@ finish_dollar_format_checking (format_check_results *res, int pointer_gap_ok) /* Retrieve the specification for a format flag. SPEC contains the specifications for format flags for the applicable kind of format. FLAG is the flag in question. If PREDICATES is NULL, the basic - spec for that flag must be retrieved and must exist. If - PREDICATES is not NULL, it is a string listing possible predicates - for the spec entry; if an entry predicated on any of these is - found, it is returned, otherwise NULL is returned. */ + spec for that flag must be retrieved and this function aborts if + it cannot be found. If PREDICATES is not NULL, it is a string listing + possible predicates for the spec entry; if an entry predicated on any + of these is found, it is returned, otherwise NULL is returned. */ static const format_flag_spec * get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates) @@ -1155,8 +1389,10 @@ get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates) else if (spec[i].predicate == 0) return &spec[i]; } - gcc_assert (predicates); - return NULL; + if (predicates == NULL) + abort (); + else + return NULL; } @@ -1165,7 +1401,7 @@ get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates) PARAMS is the list of argument values. */ static void -check_format_info (function_format_info *info, tree params) +check_format_info (int *status, function_format_info *info, tree params) { format_check_context format_ctx; unsigned HOST_WIDE_INT arg_num; @@ -1197,6 +1433,7 @@ check_format_info (function_format_info *info, tree params) format_ctx.res = &res; format_ctx.info = info; format_ctx.params = params; + format_ctx.status = status; check_function_arguments_recurse (check_format_arg, &format_ctx, format_tree, arg_num); @@ -1210,8 +1447,8 @@ check_format_info (function_format_info *info, tree params) { /* For strftime-like formats, warn for not checking the format string; but there are no arguments to check. */ - warning (OPT_Wformat_nonliteral, - "format not a string literal, format string not checked"); + if (warn_format_nonliteral) + status_warning (status, "format not a string literal, format string not checked"); } else if (info->first_arg_num != 0) { @@ -1224,15 +1461,10 @@ check_format_info (function_format_info *info, tree params) params = TREE_CHAIN (params); ++arg_num; } - if (params == 0 && warn_format_security) - warning (OPT_Wformat_security, - "format not a string literal and no format arguments"); - else if (params == 0 && warn_format_nonliteral) - warning (OPT_Wformat_nonliteral, - "format not a string literal and no format arguments"); - else - warning (OPT_Wformat_nonliteral, - "format not a string literal, argument types not checked"); + if (params == 0 && (warn_format_nonliteral || warn_format_security)) + status_warning (status, "format not a string literal and no format arguments"); + else if (warn_format_nonliteral) + status_warning (status, "format not a string literal, argument types not checked"); } } @@ -1244,21 +1476,21 @@ check_format_info (function_format_info *info, tree params) If the format is an empty string, this should be counted similarly to the case of extra format arguments. */ if (res.number_extra_args > 0 && res.number_non_literal == 0 - && res.number_other == 0) - warning (OPT_Wformat_extra_args, "too many arguments for format"); + && res.number_other == 0 && warn_format_extra_args) + status_warning (status, "too many arguments for format"); if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0 - && res.number_other == 0) - warning (OPT_Wformat_extra_args, "unused arguments in $-style format"); + && res.number_other == 0 && warn_format_extra_args) + status_warning (status, "unused arguments in $-style format"); if (res.number_empty > 0 && res.number_non_literal == 0 - && res.number_other == 0) - warning (OPT_Wformat_zero_length, "zero-length %s format string", - format_types[info->format_type].name); + && res.number_other == 0 && warn_format_zero_length) + status_warning (status, "zero-length %s format string", + format_types[info->format_type].name); if (res.number_wide > 0) - warning (OPT_Wformat, "format is a wide character string"); + status_warning (status, "format is a wide character string"); if (res.number_unterminated > 0) - warning (OPT_Wformat, "unterminated format string"); + status_warning (status, "unterminated format string"); } /* Callback from check_function_arguments_recurse to check a @@ -1270,10 +1502,11 @@ static void check_format_arg (void *ctx, tree format_tree, unsigned HOST_WIDE_INT arg_num) { - format_check_context *format_ctx = (format_check_context *) ctx; + format_check_context *format_ctx = ctx; format_check_results *res = format_ctx->res; function_format_info *info = format_ctx->info; tree params = format_ctx->params; + int *status = format_ctx->status; int format_length; HOST_WIDE_INT offset; @@ -1283,6 +1516,15 @@ check_format_arg (void *ctx, tree format_tree, if (integer_zerop (format_tree)) { + /* FIXME: this warning should go away once Marc Espie's + __attribute__((nonnull)) patch is in. Instead, checking for + nonnull attributes should probably change this function to act + specially if info == NULL and add a res->number_null entry for + that case, or maybe add a function pointer to be called at + the end instead of hardcoding check_format_info_main. */ + if (!format_types[info->format_type].null_format_ok) + status_warning (status, "null format string"); + /* Skip to first argument to check, so we can see if this format has any arguments (it shouldn't). */ while (arg_num + 1 < info->first_arg_num) @@ -1335,10 +1577,6 @@ check_format_arg (void *ctx, tree format_tree, return; } format_tree = TREE_OPERAND (format_tree, 0); - if (TREE_CODE (format_tree) == ARRAY_REF - && host_integerp (TREE_OPERAND (format_tree, 1), 0) - && (offset += tree_low_cst (TREE_OPERAND (format_tree, 1), 0)) >= 0) - format_tree = TREE_OPERAND (format_tree, 0); if (TREE_CODE (format_tree) == VAR_DECL && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE && (array_init = decl_constant_value (format_tree)) != format_tree @@ -1365,8 +1603,8 @@ check_format_arg (void *ctx, tree format_tree, if (array_size != 0) { /* Variable length arrays can't be initialized. */ - gcc_assert (TREE_CODE (array_size) == INTEGER_CST); - + if (TREE_CODE (array_size) != INTEGER_CST) + abort (); if (host_integerp (array_size, 0)) { HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size); @@ -1414,7 +1652,7 @@ check_format_arg (void *ctx, tree format_tree, will decrement it if it finds there are extra arguments, but this way need not adjust it for every return. */ res->number_other++; - check_format_info_main (res, info, format_chars, format_length, + check_format_info_main (status, res, info, format_chars, format_length, params, arg_num); } @@ -1427,7 +1665,7 @@ check_format_arg (void *ctx, tree format_tree, argument in the list of arguments. */ static void -check_format_info_main (format_check_results *res, +check_format_info_main (int *status, format_check_results *res, function_format_info *info, const char *format_chars, int format_length, tree params, unsigned HOST_WIDE_INT arg_num) @@ -1468,11 +1706,10 @@ check_format_info_main (format_check_results *res, const format_char_info *fci = NULL; char flag_chars[256]; int aflag = 0; - const char *format_start = format_chars; if (*format_chars == 0) { if (format_chars - orig_format_chars != format_length) - warning (OPT_Wformat, "embedded %<\\0%> in format"); + status_warning (status, "embedded `\\0' in format"); if (info->first_arg_num != 0 && params != 0 && has_operand_number <= 0) { @@ -1480,14 +1717,14 @@ check_format_info_main (format_check_results *res, res->number_extra_args++; } if (has_operand_number > 0) - finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK); + finish_dollar_format_checking (status, res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK); return; } if (*format_chars++ != '%') continue; if (*format_chars == 0) { - warning (OPT_Wformat, "spurious trailing %<%%%> in format"); + status_warning (status, "spurious trailing `%%' in format"); continue; } if (*format_chars == '%') @@ -1504,7 +1741,7 @@ check_format_info_main (format_check_results *res, is not used here, we can't immediately conclude this is a format without them, since it could be printf %m or scanf %*. */ int opnum; - opnum = maybe_read_dollar_number (&format_chars, 0, + opnum = maybe_read_dollar_number (status, &format_chars, 0, first_fillin_param, &main_arg_params, fki); if (opnum == -1) @@ -1515,11 +1752,6 @@ check_format_info_main (format_check_results *res, main_arg_num = opnum + info->first_arg_num - 1; } } - else if (fki->flags & FMT_FLAG_USE_DOLLAR) - { - if (avoid_dollar_number (format_chars)) - return; - } /* Read any format flags, but do not yet validate them beyond removing duplicates, since in general validation depends on the rest of @@ -1531,7 +1763,7 @@ check_format_info_main (format_check_results *res, *format_chars, NULL); if (strchr (flag_chars, *format_chars) != 0) { - warning (OPT_Wformat, "repeated %s in format", _(s->name)); + status_warning (status, "repeated %s in format", _(s->name)); } else { @@ -1544,7 +1776,7 @@ check_format_info_main (format_check_results *res, ++format_chars; if (*format_chars == 0) { - warning (OPT_Wformat, "missing fill character at end of strfmon format"); + status_warning (status, "missing fill character at end of strfmon format"); return; } } @@ -1565,7 +1797,7 @@ check_format_info_main (format_check_results *res, if (has_operand_number != 0) { int opnum; - opnum = maybe_read_dollar_number (&format_chars, + opnum = maybe_read_dollar_number (status, &format_chars, has_operand_number == 1, first_fillin_param, ¶ms, fki); @@ -1579,16 +1811,11 @@ check_format_info_main (format_check_results *res, else has_operand_number = 0; } - else - { - if (avoid_dollar_number (format_chars)) - return; - } if (info->first_arg_num != 0) { if (params == 0) { - warning (OPT_Wformat, "too few arguments for format"); + status_warning (status, "too few arguments for format"); return; } cur_param = TREE_VALUE (params); @@ -1629,7 +1856,8 @@ check_format_info_main (format_check_results *res, } if (found_width && !non_zero_width_char && (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD)) - warning (OPT_Wformat, "zero width in %s format", fki->name); + status_warning (status, "zero width in %s format", + fki->name); if (found_width) { i = strlen (flag_chars); @@ -1647,7 +1875,8 @@ check_format_info_main (format_check_results *res, flag_chars[i++] = fki->left_precision_char; flag_chars[i] = 0; if (!ISDIGIT (*format_chars)) - warning (OPT_Wformat, "empty left precision in %s format", fki->name); + status_warning (status, "empty left precision in %s format", + fki->name); while (ISDIGIT (*format_chars)) ++format_chars; } @@ -1667,7 +1896,7 @@ check_format_info_main (format_check_results *res, if (has_operand_number != 0) { int opnum; - opnum = maybe_read_dollar_number (&format_chars, + opnum = maybe_read_dollar_number (status, &format_chars, has_operand_number == 1, first_fillin_param, ¶ms, fki); @@ -1681,16 +1910,11 @@ check_format_info_main (format_check_results *res, else has_operand_number = 0; } - else - { - if (avoid_dollar_number (format_chars)) - return; - } if (info->first_arg_num != 0) { if (params == 0) { - warning (OPT_Wformat, "too few arguments for format"); + status_warning (status, "too few arguments for format"); return; } cur_param = TREE_VALUE (params); @@ -1720,7 +1944,8 @@ check_format_info_main (format_check_results *res, { if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK) && !ISDIGIT (*format_chars)) - warning (OPT_Wformat, "empty precision in %s format", fki->name); + status_warning (status, "empty precision in %s format", + fki->name); while (ISDIGIT (*format_chars)) ++format_chars; } @@ -1759,10 +1984,9 @@ check_format_info_main (format_check_results *res, { /* Warn if the length modifier is non-standard. */ if (ADJ_STD (length_chars_std) > C_STD_VER) - warning (OPT_Wformat, - "%s does not support the %qs %s length modifier", - C_STD_NAME (length_chars_std), length_chars, - fki->name); + status_warning (status, "%s does not support the `%s' %s length modifier", + C_STD_NAME (length_chars_std), length_chars, + fki->name); } } @@ -1776,7 +2000,7 @@ check_format_info_main (format_check_results *res, { const format_flag_spec *s = get_flag_spec (flag_specs, *format_chars, NULL); - warning (OPT_Wformat, "repeated %s in format", _(s->name)); + status_warning (status, "repeated %s in format", _(s->name)); } else { @@ -1796,7 +2020,7 @@ check_format_info_main (format_check_results *res, if (format_chars[1] == 's' || format_chars[1] == 'S' || format_chars[1] == '[') { - /* 'a' is used as a flag. */ + /* `a' is used as a flag. */ i = strlen (flag_chars); flag_chars[i++] = 'a'; flag_chars[i] = 0; @@ -1805,12 +2029,63 @@ check_format_info_main (format_check_results *res, } } + if (*format_chars == 'b') + { + /* There should be an int arg to control the string arg. */ + if (params == 0) + { + status_warning (status, "too few arguments for format"); + return; + } + if (info->first_arg_num != 0) + { + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + ++arg_num; + if ((TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) + != integer_type_node) + && + (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) + != unsigned_type_node)) + { + status_warning (status, "bitmap is not type int (arg %d)", + arg_num); + } + } + } + if (*format_chars == 'D') + { + /* There should be an unsigned char * arg before the string arg. */ + if (params == 0) + { + status_warning (status, "too few arguments for format"); + return; + } + if (info->first_arg_num != 0) + { + tree cur_type; + + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + ++arg_num; + cur_type = TREE_TYPE (cur_param); + if (TREE_CODE (cur_type) != POINTER_TYPE + || TYPE_MAIN_VARIANT (TREE_TYPE (cur_type)) + != unsigned_char_type_node) + { + status_warning (status, + "ethernet address is not type unsigned char * (arg %d)", + arg_num); + } + } + } + format_char = *format_chars; if (format_char == 0 || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK) && format_char == '%')) { - warning (OPT_Wformat, "conversion lacks type at end of format"); + status_warning (status, "conversion lacks type at end of format"); continue; } format_chars++; @@ -1820,19 +2095,19 @@ check_format_info_main (format_check_results *res, ++fci; if (fci->format_chars == 0) { - if (ISGRAPH (format_char)) - warning (OPT_Wformat, "unknown conversion type character %qc in format", + if (ISGRAPH(format_char)) + status_warning (status, "unknown conversion type character `%c' in format", format_char); else - warning (OPT_Wformat, "unknown conversion type character 0x%x in format", + status_warning (status, "unknown conversion type character 0x%x in format", format_char); continue; } if (pedantic) { if (ADJ_STD (fci->std) > C_STD_VER) - warning (OPT_Wformat, "%s does not support the %<%%%c%> %s format", - C_STD_NAME (fci->std), format_char, fki->name); + status_warning (status, "%s does not support the `%%%c' %s format", + C_STD_NAME (fci->std), format_char, fki->name); } /* Validate the individual flags used, removing any that are invalid. */ @@ -1847,8 +2122,8 @@ check_format_info_main (format_check_results *res, continue; if (strchr (fci->flag_chars, flag_chars[i]) == 0) { - warning (OPT_Wformat, "%s used with %<%%%c%> %s format", - _(s->name), format_char, fki->name); + status_warning (status, "%s used with `%%%c' %s format", + _(s->name), format_char, fki->name); d++; continue; } @@ -1856,8 +2131,8 @@ check_format_info_main (format_check_results *res, { const format_flag_spec *t; if (ADJ_STD (s->std) > C_STD_VER) - warning (OPT_Wformat, "%s does not support %s", - C_STD_NAME (s->std), _(s->long_name)); + status_warning (status, "%s does not support %s", + C_STD_NAME (s->std), _(s->long_name)); t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2); if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std)) { @@ -1865,10 +2140,9 @@ check_format_info_main (format_check_results *res, ? t->long_name : s->long_name); if (ADJ_STD (t->std) > C_STD_VER) - warning (OPT_Wformat, - "%s does not support %s with the %<%%%c%> %s format", - C_STD_NAME (t->std), _(long_name), - format_char, fki->name); + status_warning (status, "%s does not support %s with the `%%%c' %s format", + C_STD_NAME (t->std), _(long_name), + format_char, fki->name); } } } @@ -1899,24 +2173,22 @@ check_format_info_main (format_check_results *res, if (bad_flag_pairs[i].ignored) { if (bad_flag_pairs[i].predicate != 0) - warning (OPT_Wformat, - "%s ignored with %s and %<%%%c%> %s format", - _(s->name), _(t->name), format_char, - fki->name); + status_warning (status, "%s ignored with %s and `%%%c' %s format", + _(s->name), _(t->name), format_char, + fki->name); else - warning (OPT_Wformat, "%s ignored with %s in %s format", - _(s->name), _(t->name), fki->name); + status_warning (status, "%s ignored with %s in %s format", + _(s->name), _(t->name), fki->name); } else { if (bad_flag_pairs[i].predicate != 0) - warning (OPT_Wformat, - "use of %s and %s together with %<%%%c%> %s format", - _(s->name), _(t->name), format_char, - fki->name); + status_warning (status, "use of %s and %s together with `%%%c' %s format", + _(s->name), _(t->name), format_char, + fki->name); else - warning (OPT_Wformat, "use of %s and %s together in %s format", - _(s->name), _(t->name), fki->name); + status_warning (status, "use of %s and %s together in %s format", + _(s->name), _(t->name), fki->name); } } @@ -1934,11 +2206,10 @@ check_format_info_main (format_check_results *res, else if (strchr (fci->flags2, '2') != 0) y2k_level = 2; if (y2k_level == 3) - warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of " - "year in some locales", format_char); + status_warning (status, "`%%%c' yields only last 2 digits of year in some locales on non-BSD systems", + format_char); else if (y2k_level == 2) - warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of " - "year", format_char); + status_warning (status, "`%%%c' yields only last 2 digits of year", format_char); } if (strchr (fci->flags2, '[') != 0) @@ -1954,7 +2225,7 @@ check_format_info_main (format_check_results *res, ++format_chars; if (*format_chars != ']') /* The end of the format string was reached. */ - warning (OPT_Wformat, "no closing %<]%> for %<%%[%> format"); + status_warning (status, "no closing `]' for `%%[' format"); } wanted_type = 0; @@ -1967,15 +2238,14 @@ check_format_info_main (format_check_results *res, wanted_type_std = fci->types[length_chars_val].std; if (wanted_type == 0) { - warning (OPT_Wformat, - "use of %qs length modifier with %qc type character", - length_chars, format_char); + status_warning (status, "use of `%s' length modifier with `%c' type character", + length_chars, format_char); /* Heuristic: skip one argument when an invalid length/type combination is encountered. */ arg_num++; if (params == 0) { - warning (OPT_Wformat, "too few arguments for format"); + status_warning (status, "too few arguments for format"); return; } params = TREE_CHAIN (params); @@ -1989,15 +2259,12 @@ check_format_info_main (format_check_results *res, && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std)) { if (ADJ_STD (wanted_type_std) > C_STD_VER) - warning (OPT_Wformat, - "%s does not support the %<%%%s%c%> %s format", - C_STD_NAME (wanted_type_std), length_chars, - format_char, fki->name); + status_warning (status, "%s does not support the `%%%s%c' %s format", + C_STD_NAME (wanted_type_std), length_chars, + format_char, fki->name); } } - main_wanted_type.next = NULL; - /* Finally. . .check type of argument against desired type! */ if (info->first_arg_num == 0) continue; @@ -2007,17 +2274,13 @@ check_format_info_main (format_check_results *res, if (main_arg_num != 0) { if (suppressed) - warning (OPT_Wformat, "operand number specified with " - "suppressed assignment"); + status_warning (status, "operand number specified with suppressed assignment"); else - warning (OPT_Wformat, "operand number specified for format " - "taking no argument"); + status_warning (status, "operand number specified for format taking no argument"); } } else { - format_wanted_type *wanted_type_ptr; - if (main_arg_num != 0) { arg_num = main_arg_num; @@ -2028,77 +2291,50 @@ check_format_info_main (format_check_results *res, ++arg_num; if (has_operand_number > 0) { - warning (OPT_Wformat, "missing $ operand number in format"); + status_warning (status, "missing $ operand number in format"); return; } else has_operand_number = 0; - } - - wanted_type_ptr = &main_wanted_type; - while (fci) - { if (params == 0) { - warning (OPT_Wformat, "too few arguments for format"); + status_warning (status, "too few arguments for format"); return; } - - cur_param = TREE_VALUE (params); - params = TREE_CHAIN (params); - - wanted_type_ptr->wanted_type = wanted_type; - wanted_type_ptr->wanted_type_name = wanted_type_name; - wanted_type_ptr->pointer_count = fci->pointer_count + aflag; - wanted_type_ptr->char_lenient_flag = 0; - if (strchr (fci->flags2, 'c') != 0) - wanted_type_ptr->char_lenient_flag = 1; - wanted_type_ptr->writing_in_flag = 0; - wanted_type_ptr->reading_from_flag = 0; - if (aflag) - wanted_type_ptr->writing_in_flag = 1; - else - { - if (strchr (fci->flags2, 'W') != 0) - wanted_type_ptr->writing_in_flag = 1; - if (strchr (fci->flags2, 'R') != 0) - wanted_type_ptr->reading_from_flag = 1; - } - wanted_type_ptr->name = NULL; - wanted_type_ptr->param = cur_param; - wanted_type_ptr->arg_num = arg_num; - wanted_type_ptr->next = NULL; - if (last_wanted_type != 0) - last_wanted_type->next = wanted_type_ptr; - if (first_wanted_type == 0) - first_wanted_type = wanted_type_ptr; - last_wanted_type = wanted_type_ptr; - - fci = fci->chain; - if (fci) - { - wanted_type_ptr = GGC_NEW (format_wanted_type); - arg_num++; - wanted_type = *fci->types[length_chars_val].type; - wanted_type_name = fci->types[length_chars_val].name; - } } + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + main_wanted_type.wanted_type = wanted_type; + main_wanted_type.wanted_type_name = wanted_type_name; + main_wanted_type.pointer_count = fci->pointer_count + aflag; + main_wanted_type.char_lenient_flag = 0; + if (strchr (fci->flags2, 'c') != 0) + main_wanted_type.char_lenient_flag = 1; + main_wanted_type.writing_in_flag = 0; + main_wanted_type.reading_from_flag = 0; + if (aflag) + main_wanted_type.writing_in_flag = 1; + else + { + if (strchr (fci->flags2, 'W') != 0) + main_wanted_type.writing_in_flag = 1; + if (strchr (fci->flags2, 'R') != 0) + main_wanted_type.reading_from_flag = 1; + } + main_wanted_type.name = NULL; + main_wanted_type.param = cur_param; + main_wanted_type.arg_num = arg_num; + main_wanted_type.next = NULL; + if (last_wanted_type != 0) + last_wanted_type->next = &main_wanted_type; + if (first_wanted_type == 0) + first_wanted_type = &main_wanted_type; + last_wanted_type = &main_wanted_type; } if (first_wanted_type != 0) - check_format_types (first_wanted_type, format_start, - format_chars - format_start); + check_format_types (status, first_wanted_type); - if (main_wanted_type.next != NULL) - { - format_wanted_type *wanted_type_ptr = main_wanted_type.next; - while (wanted_type_ptr) - { - format_wanted_type *next = wanted_type_ptr->next; - ggc_free (wanted_type_ptr); - wanted_type_ptr = next; - } - } } } @@ -2106,8 +2342,7 @@ check_format_info_main (format_check_results *res, /* Check the argument types from a single format conversion (possibly including width and precision arguments). */ static void -check_format_types (format_wanted_type *types, const char *format_start, - int format_length) +check_format_types (int *status, format_wanted_type *types) { for (; types != 0; types = types->next) { @@ -2122,19 +2357,18 @@ check_format_types (format_wanted_type *types, const char *format_start, cur_type = TREE_TYPE (cur_param); if (cur_type == error_mark_node) continue; - orig_cur_type = cur_type; char_type_flag = 0; wanted_type = types->wanted_type; arg_num = types->arg_num; /* The following should not occur here. */ - gcc_assert (wanted_type); - gcc_assert (wanted_type != void_type_node || types->pointer_count); + if (wanted_type == 0) + abort (); + if (wanted_type == void_type_node && types->pointer_count == 0) + abort (); if (types->pointer_count == 0) - wanted_type = lang_hooks.types.type_promotes_to (wanted_type); - - wanted_type = TYPE_MAIN_VARIANT (wanted_type); + wanted_type = (*lang_hooks.types.type_promotes_to) (wanted_type); STRIP_NOPS (cur_param); @@ -2153,16 +2387,18 @@ check_format_types (format_wanted_type *types, const char *format_start, && i == 0 && cur_param != 0 && integer_zerop (cur_param)) - warning (OPT_Wformat, "writing through null pointer " - "(argument %d)", arg_num); + status_warning (status, + "writing through null pointer (arg %d)", + arg_num); /* Check for reading through a NULL pointer. */ if (types->reading_from_flag && i == 0 && cur_param != 0 && integer_zerop (cur_param)) - warning (OPT_Wformat, "reading through null pointer " - "(argument %d)", arg_num); + status_warning (status, + "reading through null pointer (arg %d)", + arg_num); if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR) cur_param = TREE_OPERAND (cur_param, 0); @@ -2178,11 +2414,10 @@ check_format_types (format_wanted_type *types, const char *format_start, && i == 0 && (TYPE_READONLY (cur_type) || (cur_param != 0 - && (CONSTANT_CLASS_P (cur_param) + && (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c' || (DECL_P (cur_param) && TREE_READONLY (cur_param)))))) - warning (OPT_Wformat, "writing into constant object " - "(argument %d)", arg_num); + status_warning (status, "writing into constant object (arg %d)", arg_num); /* If there are extra type qualifiers beyond the first indirection, then this makes the types technically @@ -2192,17 +2427,16 @@ check_format_types (format_wanted_type *types, const char *format_start, && (TYPE_READONLY (cur_type) || TYPE_VOLATILE (cur_type) || TYPE_RESTRICT (cur_type))) - warning (OPT_Wformat, "extra type qualifiers in format " - "argument (argument %d)", + status_warning (status, "extra type qualifiers in format argument (arg %d)", arg_num); } else { - format_type_warning (types->name, format_start, format_length, - wanted_type, types->pointer_count, - types->wanted_type_name, orig_cur_type, - arg_num); + if (types->pointer_count == 1) + status_warning (status, "format argument is not a pointer (arg %d)", arg_num); + else + status_warning (status, "format argument is not a pointer to a pointer (arg %d)", arg_num); break; } } @@ -2210,6 +2444,7 @@ check_format_types (format_wanted_type *types, const char *format_start, if (i < types->pointer_count) continue; + orig_cur_type = cur_type; cur_type = TYPE_MAIN_VARIANT (cur_type); /* Check whether the argument type is a character type. This leniency @@ -2221,9 +2456,9 @@ check_format_types (format_wanted_type *types, const char *format_start, || cur_type == unsigned_char_type_node); /* Check the type of the "real" argument, if there's a type we want. */ - if (lang_hooks.types_compatible_p (wanted_type, cur_type)) + if (wanted_type == cur_type) continue; - /* If we want 'void *', allow any pointer type. + /* If we want `void *', allow any pointer type. (Anything else would already have got a warning.) With -pedantic, only allow pointers to void and to character types. */ @@ -2236,126 +2471,116 @@ check_format_types (format_wanted_type *types, const char *format_start, a second level of indirection. */ if (TREE_CODE (wanted_type) == INTEGER_TYPE && TREE_CODE (cur_type) == INTEGER_TYPE - && (!pedantic || i == 0 || (i == 1 && char_type_flag)) - && (TYPE_UNSIGNED (wanted_type) + && (! pedantic || i == 0 || (i == 1 && char_type_flag)) + && (TREE_UNSIGNED (wanted_type) ? wanted_type == c_common_unsigned_type (cur_type) : wanted_type == c_common_signed_type (cur_type))) continue; /* Likewise, "signed char", "unsigned char" and "char" are equivalent but the above test won't consider them equivalent. */ if (wanted_type == char_type_node - && (!pedantic || i < 2) + && (! pedantic || i < 2) && char_type_flag) continue; /* Now we have a type mismatch. */ - format_type_warning (types->name, format_start, format_length, - wanted_type, types->pointer_count, - types->wanted_type_name, orig_cur_type, arg_num); - } -} + { + const char *this; + const char *that; + tree tmp; + + tmp = TYPE_NAME (wanted_type); + if (TREE_CODE (tmp) == TYPE_DECL) + tmp = DECL_NAME (tmp); + this = IDENTIFIER_POINTER (tmp); + + that = 0; + if (TYPE_NAME (orig_cur_type) != 0 + && TREE_CODE (orig_cur_type) != INTEGER_TYPE + && !(TREE_CODE (orig_cur_type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (orig_cur_type)) == INTEGER_TYPE)) + { + tmp = TYPE_NAME (orig_cur_type); + if (TREE_CODE (tmp) == TYPE_DECL) + tmp = DECL_NAME (tmp); + if (tmp) + that = IDENTIFIER_POINTER (tmp); + } + /* A nameless type can't possibly match what the format wants. + So there will be a warning for it. + Make up a string to describe vaguely what it is. */ + if (that == 0) + { + if (TREE_CODE (orig_cur_type) == POINTER_TYPE) + that = _("pointer"); + else + that = _("different type"); + } -/* Give a warning about a format argument of different type from that - expected. DESCR is a description such as "field precision", or - NULL for an ordinary format. For an ordinary format, FORMAT_START - points to where the format starts in the format string and - FORMAT_LENGTH is its length. WANTED_TYPE is the type the argument - should have after POINTER_COUNT pointer dereferences. - WANTED_NAME_NAME is a possibly more friendly name of WANTED_TYPE, - or NULL if the ordinary name of the type should be used. ARG_TYPE - is the type of the actual argument. ARG_NUM is the number of that - argument. */ -static void -format_type_warning (const char *descr, const char *format_start, - int format_length, tree wanted_type, int pointer_count, - const char *wanted_type_name, tree arg_type, int arg_num) -{ - char *p; - /* If ARG_TYPE is a typedef with a misleading name (for example, - size_t but not the standard size_t expected by printf %zu), avoid - printing the typedef name. */ - if (wanted_type_name - && TYPE_NAME (arg_type) - && TREE_CODE (TYPE_NAME (arg_type)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (arg_type)) - && !strcmp (wanted_type_name, - lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2))) - arg_type = TYPE_MAIN_VARIANT (arg_type); - /* The format type and name exclude any '*' for pointers, so those - must be formatted manually. For all the types we currently have, - this is adequate, but formats taking pointers to functions or - arrays would require the full type to be built up in order to - print it with %T. */ - p = (char *) alloca (pointer_count + 2); - if (pointer_count == 0) - p[0] = 0; - else if (c_dialect_cxx ()) - { - memset (p, '*', pointer_count); - p[pointer_count] = 0; - } - else - { - p[0] = ' '; - memset (p + 1, '*', pointer_count); - p[pointer_count + 1] = 0; - } - if (wanted_type_name) - { - if (descr) - warning (OPT_Wformat, "%s should have type %<%s%s%>, " - "but argument %d has type %qT", - descr, wanted_type_name, p, arg_num, arg_type); - else - warning (OPT_Wformat, "format %q.*s expects type %<%s%s%>, " - "but argument %d has type %qT", - format_length, format_start, wanted_type_name, p, - arg_num, arg_type); - } - else - { - if (descr) - warning (OPT_Wformat, "%s should have type %<%T%s%>, " - "but argument %d has type %qT", - descr, wanted_type, p, arg_num, arg_type); - else - warning (OPT_Wformat, "format %q.*s expects type %<%T%s%>, " - "but argument %d has type %qT", - format_length, format_start, wanted_type, p, arg_num, arg_type); + /* Make the warning better in case of mismatch of int vs long. */ + if (TREE_CODE (orig_cur_type) == INTEGER_TYPE + && TREE_CODE (wanted_type) == INTEGER_TYPE + && TYPE_PRECISION (orig_cur_type) == TYPE_PRECISION (wanted_type) + && TYPE_NAME (orig_cur_type) != 0 + && TREE_CODE (TYPE_NAME (orig_cur_type)) == TYPE_DECL) + that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (orig_cur_type))); + + if (strcmp (this, that) != 0) + { + /* There may be a better name for the format, e.g. size_t, + but we should allow for programs with a perverse typedef + making size_t something other than what the compiler + thinks. */ + if (types->wanted_type_name != 0 + && strcmp (types->wanted_type_name, that) != 0) + this = types->wanted_type_name; + if (types->name != 0) + status_warning (status, "%s is not type %s (arg %d)", types->name, this, + arg_num); + else + status_warning (status, "%s format, %s arg (arg %d)", this, that, arg_num); + } + } } } - /* Given a format_char_info array FCI, and a character C, this function returns the index into the conversion_specs where that specifier's - data is located. The character must exist. */ + data is located. If the character isn't found it aborts. */ static unsigned int find_char_info_specifier_index (const format_char_info *fci, int c) { - unsigned i; - - for (i = 0; fci->format_chars; i++, fci++) - if (strchr (fci->format_chars, c)) - return i; - + unsigned int i = 0; + + while (fci->format_chars) + { + if (strchr (fci->format_chars, c)) + return i; + i++; fci++; + } + /* We shouldn't be looking for a non-existent specifier. */ - gcc_unreachable (); + abort (); } /* Given a format_length_info array FLI, and a character C, this function returns the index into the conversion_specs where that - modifier's data is located. The character must exist. */ + modifier's data is located. If the character isn't found it + aborts. */ static unsigned int find_length_info_modifier_index (const format_length_info *fli, int c) { - unsigned i; - - for (i = 0; fli->name; i++, fli++) - if (strchr (fli->name, c)) - return i; - + unsigned int i = 0; + + while (fli->name) + { + if (strchr (fli->name, c)) + return i; + i++; fli++; + } + /* We shouldn't be looking for a non-existent modifier. */ - gcc_unreachable (); + abort (); } /* Determine the type of HOST_WIDE_INT in the code being compiled for @@ -2365,12 +2590,12 @@ static void init_dynamic_asm_fprintf_info (void) { static tree hwi; - + if (!hwi) { format_length_info *new_asm_fprintf_length_specs; unsigned int i; - + /* Find the underlying type for HOST_WIDE_INT. For the %w length modifier to work, one must have issued: "typedef HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code @@ -2378,27 +2603,27 @@ init_dynamic_asm_fprintf_info (void) hwi = maybe_get_identifier ("__gcc_host_wide_int__"); if (!hwi) { - error ("%<__gcc_host_wide_int__%> is not defined as a type"); + error ("'__gcc_host_wide_int__' is not defined as a type"); return; } hwi = identifier_global_value (hwi); if (!hwi || TREE_CODE (hwi) != TYPE_DECL) { - error ("%<__gcc_host_wide_int__%> is not defined as a type"); + error ("'__gcc_host_wide_int__' is not defined as a type"); return; } hwi = DECL_ORIGINAL_TYPE (hwi); - gcc_assert (hwi); + if (!hwi) + abort (); if (hwi != long_integer_type_node && hwi != long_long_integer_type_node) { - error ("%<__gcc_host_wide_int__%> is not defined as %<long%>" - " or %<long long%>"); + error ("'__gcc_host_wide_int__' is not defined as 'long'" + " or 'long long'"); return; } /* Create a new (writable) copy of asm_fprintf_length_specs. */ - new_asm_fprintf_length_specs = (format_length_info *) - xmemdup (asm_fprintf_length_specs, + new_asm_fprintf_length_specs = xmemdup (asm_fprintf_length_specs, sizeof (asm_fprintf_length_specs), sizeof (asm_fprintf_length_specs)); @@ -2409,7 +2634,7 @@ init_dynamic_asm_fprintf_info (void) else if (hwi == long_long_integer_type_node) new_asm_fprintf_length_specs[i].index = FMT_LEN_ll; else - gcc_unreachable (); + abort (); /* Assign the new data for use. */ dynamic_format_types[asm_fprintf_format_type].length_char_specs = @@ -2417,55 +2642,6 @@ init_dynamic_asm_fprintf_info (void) } } -/* Determine the type of a "locus" in the code being compiled for use - in GCC's __gcc_gfc__ custom format attribute. You must have set - dynamic_format_types before calling this function. */ -static void -init_dynamic_gfc_info (void) -{ - static tree locus; - - if (!locus) - { - static format_char_info *gfc_fci; - - /* For the GCC __gcc_gfc__ custom format specifier to work, one - must have declared 'locus' prior to using this attribute. If - we haven't seen this declarations then you shouldn't use the - specifier requiring that type. */ - if ((locus = maybe_get_identifier ("locus"))) - { - locus = identifier_global_value (locus); - if (locus) - { - if (TREE_CODE (locus) != TYPE_DECL) - { - error ("%<locus%> is not defined as a type"); - locus = 0; - } - else - locus = TREE_TYPE (locus); - } - } - - /* Assign the new data for use. */ - - /* Handle the __gcc_gfc__ format specifics. */ - if (!gfc_fci) - dynamic_format_types[gcc_gfc_format_type].conversion_specs = - gfc_fci = (format_char_info *) - xmemdup (gcc_gfc_char_table, - sizeof (gcc_gfc_char_table), - sizeof (gcc_gfc_char_table)); - if (locus) - { - const unsigned i = find_char_info_specifier_index (gfc_fci, 'L'); - gfc_fci[i].types[0].type = &locus; - gfc_fci[i].pointer_count = 1; - } - } -} - /* Determine the types of "tree" and "location_t" in the code being compiled for use in GCC's diagnostic custom format attributes. You must have set dynamic_format_types before calling this function. */ @@ -2473,15 +2649,15 @@ static void init_dynamic_diag_info (void) { static tree t, loc, hwi; - + if (!loc || !t || !hwi) { - static format_char_info *diag_fci, *tdiag_fci, *cdiag_fci, *cxxdiag_fci; + static format_char_info *diag_fci, *cdiag_fci, *cxxdiag_fci; static format_length_info *diag_ls; unsigned int i; /* For the GCC-diagnostics custom format specifiers to work, one - must have declared 'tree' and/or 'location_t' prior to using + must have declared `tree' and/or `location_t' prior to using those attributes. If we haven't seen these declarations then you shouldn't use the specifiers requiring these types. However we don't force a hard ICE because we may see only one @@ -2493,7 +2669,7 @@ init_dynamic_diag_info (void) { if (TREE_CODE (loc) != TYPE_DECL) { - error ("%<location_t%> is not defined as a type"); + error ("'location_t' is not defined as a type"); loc = 0; } else @@ -2501,7 +2677,7 @@ init_dynamic_diag_info (void) } } - /* We need to grab the underlying 'union tree_node' so peek into + /* We need to grab the underlying `union tree_node' so peek into an extra type level. */ if ((t = maybe_get_identifier ("tree"))) { @@ -2510,19 +2686,19 @@ init_dynamic_diag_info (void) { if (TREE_CODE (t) != TYPE_DECL) { - error ("%<tree%> is not defined as a type"); + error ("'tree' is not defined as a type"); t = 0; } else if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) { - error ("%<tree%> is not defined as a pointer type"); + error ("'tree' is not defined as a pointer type"); t = 0; } else t = TREE_TYPE (TREE_TYPE (t)); } } - + /* Find the underlying type for HOST_WIDE_INT. For the %w length modifier to work, one must have issued: "typedef HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code @@ -2534,38 +2710,37 @@ init_dynamic_diag_info (void) { if (TREE_CODE (hwi) != TYPE_DECL) { - error ("%<__gcc_host_wide_int__%> is not defined as a type"); + error ("'__gcc_host_wide_int__' is not defined as a type"); hwi = 0; } else { hwi = DECL_ORIGINAL_TYPE (hwi); - gcc_assert (hwi); + if (!hwi) + abort (); if (hwi != long_integer_type_node && hwi != long_long_integer_type_node) { - error ("%<__gcc_host_wide_int__%> is not defined" - " as %<long%> or %<long long%>"); + error ("'__gcc_host_wide_int__' is not defined" + " as 'long' or 'long long'"); hwi = 0; } } } } - + /* Assign the new data for use. */ /* All the GCC diag formats use the same length specs. */ - if (!diag_ls) + if (! diag_ls) dynamic_format_types[gcc_diag_format_type].length_char_specs = - dynamic_format_types[gcc_tdiag_format_type].length_char_specs = dynamic_format_types[gcc_cdiag_format_type].length_char_specs = dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs = - diag_ls = (format_length_info *) - xmemdup (gcc_diag_length_specs, + diag_ls = xmemdup (gcc_diag_length_specs, sizeof (gcc_diag_length_specs), - sizeof (gcc_diag_length_specs)); + sizeof (gcc_diag_length_specs)); if (hwi) - { + { /* HOST_WIDE_INT must be one of 'long' or 'long long'. */ i = find_length_info_modifier_index (diag_ls, 'w'); if (hwi == long_integer_type_node) @@ -2573,68 +2748,42 @@ init_dynamic_diag_info (void) else if (hwi == long_long_integer_type_node) diag_ls[i].index = FMT_LEN_ll; else - gcc_unreachable (); + abort (); } /* Handle the __gcc_diag__ format specifics. */ - if (!diag_fci) + if (! diag_fci) dynamic_format_types[gcc_diag_format_type].conversion_specs = - diag_fci = (format_char_info *) - xmemdup (gcc_diag_char_table, - sizeof (gcc_diag_char_table), - sizeof (gcc_diag_char_table)); + diag_fci = xmemdup (gcc_diag_char_table, + sizeof(gcc_diag_char_table), + sizeof(gcc_diag_char_table)); if (loc) - { + { i = find_char_info_specifier_index (diag_fci, 'H'); diag_fci[i].types[0].type = &loc; diag_fci[i].pointer_count = 1; } if (t) - { + { i = find_char_info_specifier_index (diag_fci, 'J'); diag_fci[i].types[0].type = &t; diag_fci[i].pointer_count = 1; } - /* Handle the __gcc_tdiag__ format specifics. */ - if (!tdiag_fci) - dynamic_format_types[gcc_tdiag_format_type].conversion_specs = - tdiag_fci = (format_char_info *) - xmemdup (gcc_tdiag_char_table, - sizeof (gcc_tdiag_char_table), - sizeof (gcc_tdiag_char_table)); - if (loc) - { - i = find_char_info_specifier_index (tdiag_fci, 'H'); - tdiag_fci[i].types[0].type = &loc; - tdiag_fci[i].pointer_count = 1; - } - if (t) - { - /* All specifiers taking a tree share the same struct. */ - i = find_char_info_specifier_index (tdiag_fci, 'D'); - tdiag_fci[i].types[0].type = &t; - tdiag_fci[i].pointer_count = 1; - i = find_char_info_specifier_index (tdiag_fci, 'J'); - tdiag_fci[i].types[0].type = &t; - tdiag_fci[i].pointer_count = 1; - } - /* Handle the __gcc_cdiag__ format specifics. */ - if (!cdiag_fci) + if (! cdiag_fci) dynamic_format_types[gcc_cdiag_format_type].conversion_specs = - cdiag_fci = (format_char_info *) - xmemdup (gcc_cdiag_char_table, - sizeof (gcc_cdiag_char_table), - sizeof (gcc_cdiag_char_table)); + cdiag_fci = xmemdup (gcc_cdiag_char_table, + sizeof(gcc_cdiag_char_table), + sizeof(gcc_cdiag_char_table)); if (loc) - { + { i = find_char_info_specifier_index (cdiag_fci, 'H'); cdiag_fci[i].types[0].type = &loc; cdiag_fci[i].pointer_count = 1; } if (t) - { + { /* All specifiers taking a tree share the same struct. */ i = find_char_info_specifier_index (cdiag_fci, 'D'); cdiag_fci[i].types[0].type = &t; @@ -2645,20 +2794,19 @@ init_dynamic_diag_info (void) } /* Handle the __gcc_cxxdiag__ format specifics. */ - if (!cxxdiag_fci) + if (! cxxdiag_fci) dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs = - cxxdiag_fci = (format_char_info *) - xmemdup (gcc_cxxdiag_char_table, - sizeof (gcc_cxxdiag_char_table), - sizeof (gcc_cxxdiag_char_table)); + cxxdiag_fci = xmemdup (gcc_cxxdiag_char_table, + sizeof(gcc_cxxdiag_char_table), + sizeof(gcc_cxxdiag_char_table)); if (loc) - { + { i = find_char_info_specifier_index (cxxdiag_fci, 'H'); cxxdiag_fci[i].types[0].type = &loc; cxxdiag_fci[i].pointer_count = 1; } if (t) - { + { /* All specifiers taking a tree share the same struct. */ i = find_char_info_specifier_index (cxxdiag_fci, 'D'); cxxdiag_fci[i].types[0].type = &t; @@ -2670,37 +2818,16 @@ init_dynamic_diag_info (void) } } -#ifdef TARGET_FORMAT_TYPES -extern const format_kind_info TARGET_FORMAT_TYPES[]; -#endif - /* Handle a "format" attribute; arguments as in struct attribute_spec.handler. */ tree -handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args, +handle_format_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args, int flags, bool *no_add_attrs) { tree type = *node; function_format_info info; tree argument; -#ifdef TARGET_FORMAT_TYPES - /* If the target provides additional format types, we need to - add them to FORMAT_TYPES at first use. */ - if (TARGET_FORMAT_TYPES != NULL && !dynamic_format_types) - { - dynamic_format_types = xmalloc ((n_format_types + TARGET_N_FORMAT_TYPES) - * sizeof (dynamic_format_types[0])); - memcpy (dynamic_format_types, format_types_orig, - sizeof (format_types_orig)); - memcpy (&dynamic_format_types[n_format_types], TARGET_FORMAT_TYPES, - TARGET_N_FORMAT_TYPES * sizeof (dynamic_format_types[0])); - - format_types = dynamic_format_types; - n_format_types += TARGET_N_FORMAT_TYPES; - } -#endif - if (!decode_format_attr (args, &info, 0)) { *no_add_attrs = true; @@ -2726,7 +2853,7 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args, if (arg_num != info.first_arg_num) { if (!(flags & (int) ATTR_FLAG_BUILT_IN)) - error ("args to be formatted is not %<...%>"); + error ("args to be formatted is not '...'"); *no_add_attrs = true; return NULL_TREE; } @@ -2743,36 +2870,29 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args, /* If this is a custom GCC-internal format type, we have to initialize certain bits a runtime. */ if (info.format_type == asm_fprintf_format_type - || info.format_type == gcc_gfc_format_type || info.format_type == gcc_diag_format_type - || info.format_type == gcc_tdiag_format_type || info.format_type == gcc_cdiag_format_type || info.format_type == gcc_cxxdiag_format_type) { /* Our first time through, we have to make sure that our - format_type data is allocated dynamically and is modifiable. */ + format_type data is allocated dynamically and is modifiable. */ if (!dynamic_format_types) - format_types = dynamic_format_types = (format_kind_info *) + format_types = dynamic_format_types = xmemdup (format_types_orig, sizeof (format_types_orig), sizeof (format_types_orig)); /* If this is format __asm_fprintf__, we have to initialize - GCC's notion of HOST_WIDE_INT for checking %wd. */ + GCC's notion of HOST_WIDE_INT for checking %wd. */ if (info.format_type == asm_fprintf_format_type) - init_dynamic_asm_fprintf_info (); - /* If this is format __gcc_gfc__, we have to initialize GCC's - notion of 'locus' at runtime for %L. */ - else if (info.format_type == gcc_gfc_format_type) - init_dynamic_gfc_info (); + init_dynamic_asm_fprintf_info(); /* If this is one of the diagnostic attributes, then we have to - initialize 'location_t' and 'tree' at runtime. */ + initialize `location_t' and `tree' at runtime. */ else if (info.format_type == gcc_diag_format_type - || info.format_type == gcc_tdiag_format_type || info.format_type == gcc_cdiag_format_type || info.format_type == gcc_cxxdiag_format_type) - init_dynamic_diag_info (); + init_dynamic_diag_info(); else - gcc_unreachable (); + abort(); } return NULL_TREE; diff --git a/contrib/gcc/c-lex.c b/contrib/gcc/c-lex.c index 108bc5c..aba571f 100644 --- a/contrib/gcc/c-lex.c +++ b/contrib/gcc/c-lex.c @@ -1,7 +1,6 @@ /* Mainly the interface between cpplib and the C front ends. Copyright (C) 1987, 1988, 1989, 1992, 1994, 1995, 1996, 1997 - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 - Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -17,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #include "config.h" #include "system.h" @@ -28,6 +27,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "real.h" #include "rtl.h" #include "tree.h" +#include "expr.h" #include "input.h" #include "output.h" #include "c-tree.h" @@ -42,29 +42,28 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "splay-tree.h" #include "debug.h" +/* The current line map. */ +static const struct line_map *map; + /* We may keep statistics about how long which files took to compile. */ static int header_time, body_time; static splay_tree file_info_tree; -int pending_lang_change; /* If we need to switch languages - C++ only */ -int c_header_level; /* depth in C headers - C++ only */ +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE TYPE_PRECISION (wchar_type_node) -/* If we need to translate characters received. This is tri-state: - 0 means use only the untranslated string; 1 means use only - the translated string; -1 means chain the translated string - to the untranslated one. */ -int c_lex_string_translate = 1; +/* Number of bytes in a wide character. */ +#define WCHAR_BYTES (WCHAR_TYPE_SIZE / BITS_PER_UNIT) -/* True if strings should be passed to the caller of c_lex completely - unmolested (no concatenation, no translation). */ -bool c_lex_return_raw_strings = false; +int pending_lang_change; /* If we need to switch languages - C++ only */ +int c_header_level; /* depth in C headers - C++ only */ static tree interpret_integer (const cpp_token *, unsigned int); static tree interpret_float (const cpp_token *, unsigned int); -static enum integer_type_kind narrowest_unsigned_type - (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int); -static enum integer_type_kind narrowest_signed_type - (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int); +static enum integer_type_kind + narrowest_unsigned_type (tree, unsigned int); +static enum integer_type_kind + narrowest_signed_type (tree, unsigned int); static enum cpp_ttype lex_string (const cpp_token *, tree *, bool); static tree lex_charconst (const cpp_token *); static void update_header_times (const char *); @@ -81,8 +80,10 @@ init_c_lex (void) struct cpp_callbacks *cb; struct c_fileinfo *toplevel; - /* The get_fileinfo data structure must be initialized before - cpp_read_main_file is called. */ + /* Set up filename timing. Must happen before cpp_read_main_file. */ + file_info_tree = splay_tree_new ((splay_tree_compare_fn)strcmp, + 0, + (splay_tree_delete_value_fn)free); toplevel = get_fileinfo ("<top level>"); if (flag_detailed_statistics) { @@ -101,8 +102,8 @@ init_c_lex (void) /* Set the debug callbacks if we can use them. */ if (debug_info_level == DINFO_LEVEL_VERBOSE - && (write_symbols == DWARF2_DEBUG - || write_symbols == VMS_AND_DWARF2_DEBUG)) + && (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG + || write_symbols == VMS_AND_DWARF2_DEBUG)) { cb->define = cb_define; cb->undef = cb_undef; @@ -115,16 +116,11 @@ get_fileinfo (const char *name) splay_tree_node n; struct c_fileinfo *fi; - if (!file_info_tree) - file_info_tree = splay_tree_new ((splay_tree_compare_fn) strcmp, - 0, - (splay_tree_delete_value_fn) free); - n = splay_tree_lookup (file_info_tree, (splay_tree_key) name); if (n) return (struct c_fileinfo *) n->value; - fi = XNEW (struct c_fileinfo); + fi = xmalloc (sizeof (struct c_fileinfo)); fi->time = 0; fi->interface_only = 0; fi->interface_unknown = 1; @@ -149,7 +145,7 @@ update_header_times (const char *name) } static int -dump_one_header (splay_tree_node n, void * ARG_UNUSED (dummy)) +dump_one_header (splay_tree_node n, void *dummy ATTRIBUTE_UNUSED) { print_time ((const char *) n->key, ((struct c_fileinfo *) n->value)->time); @@ -167,26 +163,26 @@ dump_time_statistics (void) print_time ("header files (total)", header_time); print_time ("main file (total)", this_time - body_time); fprintf (stderr, "ratio = %g : 1\n", - (double) header_time / (double) (this_time - body_time)); + (double)header_time / (double)(this_time - body_time)); fprintf (stderr, "\n******\n"); splay_tree_foreach (file_info_tree, dump_one_header, 0); } static void -cb_ident (cpp_reader * ARG_UNUSED (pfile), - unsigned int ARG_UNUSED (line), - const cpp_string * ARG_UNUSED (str)) +cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, + unsigned int line ATTRIBUTE_UNUSED, + const cpp_string *str ATTRIBUTE_UNUSED) { #ifdef ASM_OUTPUT_IDENT - if (!flag_no_ident) + if (! flag_no_ident) { /* Convert escapes in the string. */ cpp_string cstr = { 0, 0 }; if (cpp_interpret_string (pfile, str, 1, &cstr, false)) { ASM_OUTPUT_IDENT (asm_out_file, (const char *) cstr.text); - free ((void *) cstr.text); + free ((void *)cstr.text); } } #endif @@ -195,44 +191,34 @@ cb_ident (cpp_reader * ARG_UNUSED (pfile), /* Called at the start of every non-empty line. TOKEN is the first lexed token on the line. Used for diagnostic line numbers. */ static void -cb_line_change (cpp_reader * ARG_UNUSED (pfile), const cpp_token *token, +cb_line_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const cpp_token *token, int parsing_args) { - if (token->type != CPP_EOF && !parsing_args) -#ifdef USE_MAPPED_LOCATION - input_location = token->src_loc; -#else - { - source_location loc = token->src_loc; - const struct line_map *map = linemap_lookup (&line_table, loc); - input_line = SOURCE_LINE (map, loc); - } -#endif + if (token->type == CPP_EOF || parsing_args) + return; + + input_line = SOURCE_LINE (map, token->line); } void fe_file_change (const struct line_map *new_map) { if (new_map == NULL) - return; + { + map = NULL; + return; + } if (new_map->reason == LC_ENTER) { /* Don't stack the main buffer on the input stack; we already did in compile_file. */ - if (!MAIN_FILE_P (new_map)) + if (map != NULL) { -#ifdef USE_MAPPED_LOCATION - int included_at = LAST_SOURCE_LINE_LOCATION (new_map - 1); - - input_location = included_at; - push_srcloc (new_map->start_location); -#else - int included_at = LAST_SOURCE_LINE (new_map - 1); + int included_at = SOURCE_LINE (new_map - 1, new_map->from_line - 1); input_line = included_at; push_srcloc (new_map->to_file, 1); -#endif (*debug_hooks->start_source_file) (included_at, new_map->to_file); #ifndef NO_IMPLICIT_EXTERN_C if (c_header_level) @@ -251,7 +237,7 @@ fe_file_change (const struct line_map *new_map) if (c_header_level && --c_header_level == 0) { if (new_map->sysp == 2) - warning (0, "badly nested C headers from preprocessor"); + warning ("badly nested C headers from preprocessor"); --pending_lang_change; } #endif @@ -262,16 +248,16 @@ fe_file_change (const struct line_map *new_map) update_header_times (new_map->to_file); in_system_header = new_map->sysp != 0; -#ifdef USE_MAPPED_LOCATION - input_location = new_map->start_location; -#else input_filename = new_map->to_file; input_line = new_map->to_line; -#endif + map = new_map; + + /* Hook for C++. */ + extract_interface_info (); } static void -cb_def_pragma (cpp_reader *pfile, source_location loc) +cb_def_pragma (cpp_reader *pfile, unsigned int line) { /* Issue a warning message if we have been asked to do so. Ignore unknown pragmas in system headers unless an explicit @@ -280,14 +266,6 @@ cb_def_pragma (cpp_reader *pfile, source_location loc) { const unsigned char *space, *name; const cpp_token *s; -#ifndef USE_MAPPED_LOCATION - location_t fe_loc; - const struct line_map *map = linemap_lookup (&line_table, loc); - fe_loc.file = map->to_file; - fe_loc.line = SOURCE_LINE (map, loc); -#else - location_t fe_loc = loc; -#endif space = name = (const unsigned char *) ""; s = cpp_get_token (pfile); @@ -299,58 +277,54 @@ cb_def_pragma (cpp_reader *pfile, source_location loc) name = cpp_token_as_text (pfile, s); } - warning (OPT_Wunknown_pragmas, "%Hignoring #pragma %s %s", - &fe_loc, space, name); + input_line = SOURCE_LINE (map, line); + warning ("ignoring #pragma %s %s", space, name); } } /* #define callback for DWARF and DWARF2 debug info. */ static void -cb_define (cpp_reader *pfile, source_location loc, cpp_hashnode *node) +cb_define (cpp_reader *pfile, unsigned int line, cpp_hashnode *node) { - const struct line_map *map = linemap_lookup (&line_table, loc); - (*debug_hooks->define) (SOURCE_LINE (map, loc), + (*debug_hooks->define) (SOURCE_LINE (map, line), (const char *) cpp_macro_definition (pfile, node)); } /* #undef callback for DWARF and DWARF2 debug info. */ static void -cb_undef (cpp_reader * ARG_UNUSED (pfile), source_location loc, +cb_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, unsigned int line, cpp_hashnode *node) { - const struct line_map *map = linemap_lookup (&line_table, loc); - (*debug_hooks->undef) (SOURCE_LINE (map, loc), + (*debug_hooks->undef) (SOURCE_LINE (map, line), (const char *) NODE_NAME (node)); } -/* Read a token and return its type. Fill *VALUE with its value, if - applicable. Fill *CPP_FLAGS with the token's flags, if it is - non-NULL. */ +static inline const cpp_token * +get_nonpadding_token (void) +{ + const cpp_token *tok; + timevar_push (TV_CPP); + do + tok = cpp_get_token (parse_in); + while (tok->type == CPP_PADDING); + timevar_pop (TV_CPP); -enum cpp_ttype -c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags) + return tok; +} + +int +c_lex_with_flags (tree *value, unsigned char *cpp_flags) { - static bool no_more_pch; const cpp_token *tok; - enum cpp_ttype type; - unsigned char add_flags = 0; + location_t atloc; + static bool no_more_pch; - timevar_push (TV_CPP); retry: - tok = cpp_get_token (parse_in); - type = tok->type; + tok = get_nonpadding_token (); retry_after_at: -#ifdef USE_MAPPED_LOCATION - *loc = tok->src_loc; -#else - *loc = input_location; -#endif - switch (type) + switch (tok->type) { - case CPP_PADDING: - goto retry; - case CPP_NAME: *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node)); break; @@ -364,14 +338,9 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags) case CPP_N_INVALID: /* cpplib has issued an error. */ *value = error_mark_node; - errorcount++; break; case CPP_N_INTEGER: - /* C++ uses '0' to mark virtual functions as pure. - Set PURE_ZERO to pass this information to the C++ parser. */ - if (tok->val.str.len == 1 && *tok->val.str.text == '0') - add_flags = PURE_ZERO; *value = interpret_integer (tok, flags); break; @@ -380,59 +349,41 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags) break; default: - gcc_unreachable (); + abort (); } } break; case CPP_ATSIGN: /* An @ may give the next token special significance in Objective-C. */ + atloc = input_location; + tok = get_nonpadding_token (); if (c_dialect_objc ()) { - location_t atloc = input_location; - - retry_at: - tok = cpp_get_token (parse_in); - type = tok->type; - switch (type) + tree val; + switch (tok->type) { - case CPP_PADDING: - goto retry_at; - - case CPP_STRING: - case CPP_WSTRING: - type = lex_string (tok, value, true); - break; - case CPP_NAME: - *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node)); - if (objc_is_reserved_word (*value)) + val = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node)); + if (C_IS_RESERVED_WORD (val) + && OBJC_IS_AT_KEYWORD (C_RID_CODE (val))) { - type = CPP_AT_NAME; - break; + *value = val; + return CPP_AT_NAME; } - /* FALLTHROUGH */ + break; - default: - /* ... or not. */ - error ("%Hstray %<@%> in program", &atloc); - goto retry_after_at; + case CPP_STRING: + case CPP_WSTRING: + return lex_string (tok, value, true); + + default: break; } - break; } - /* FALLTHROUGH */ - case CPP_HASH: - case CPP_PASTE: - { - unsigned char name[4]; - - *cpp_spell_token (parse_in, tok, name, true) = 0; - - error ("stray %qs in program", name); - } - - goto retry; + /* ... or not. */ + error ("%Hstray '@' in program", &atloc); + goto retry_after_at; case CPP_OTHER: { @@ -441,9 +392,9 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags) if (c == '"' || c == '\'') error ("missing terminating %c character", (int) c); else if (ISGRAPH (c)) - error ("stray %qc in program", (int) c); + error ("stray '%c' in program", (int) c); else - error ("stray %<\\%o%> in program", (int) c); + error ("stray '\\%o' in program", (int) c); } goto retry; @@ -454,51 +405,42 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags) case CPP_STRING: case CPP_WSTRING: - if (!c_lex_return_raw_strings) - { - type = lex_string (tok, value, false); - break; - } - *value = build_string (tok->val.str.len, (char *) tok->val.str.text); - break; - - case CPP_PRAGMA: - *value = build_int_cst (NULL, tok->val.pragma); + return lex_string (tok, value, false); break; /* These tokens should not be visible outside cpplib. */ case CPP_HEADER_NAME: case CPP_COMMENT: case CPP_MACRO_ARG: - gcc_unreachable (); + abort (); default: *value = NULL_TREE; break; } - if (cpp_flags) - *cpp_flags = tok->flags | add_flags; - - if (!no_more_pch) + if (! no_more_pch) { no_more_pch = true; c_common_no_more_pch (); } - timevar_pop (TV_CPP); + if (cpp_flags) + *cpp_flags = tok->flags; + return tok->type; +} - return type; +int +c_lex (tree *value) +{ + return c_lex_with_flags (value, NULL); } /* Returns the narrowest C-visible unsigned type, starting with the - minimum specified by FLAGS, that can fit HIGH:LOW, or itk_none if + minimum specified by FLAGS, that can fit VALUE, or itk_none if there isn't one. */ - static enum integer_type_kind -narrowest_unsigned_type (unsigned HOST_WIDE_INT low, - unsigned HOST_WIDE_INT high, - unsigned int flags) +narrowest_unsigned_type (tree value, unsigned int flags) { enum integer_type_kind itk; @@ -509,23 +451,20 @@ narrowest_unsigned_type (unsigned HOST_WIDE_INT low, else itk = itk_unsigned_long_long; - for (; itk < itk_none; itk += 2 /* skip unsigned types */) - { - tree upper = TYPE_MAX_VALUE (integer_types[itk]); + /* int_fits_type_p must think the type of its first argument is + wider than its second argument, or it won't do the proper check. */ + TREE_TYPE (value) = widest_unsigned_literal_type_node; - if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) > high - || ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) == high - && TREE_INT_CST_LOW (upper) >= low)) - return itk; - } + for (; itk < itk_none; itk += 2 /* skip unsigned types */) + if (int_fits_type_p (value, integer_types[itk])) + return itk; return itk_none; } /* Ditto, but narrowest signed type. */ static enum integer_type_kind -narrowest_signed_type (unsigned HOST_WIDE_INT low, - unsigned HOST_WIDE_INT high, unsigned int flags) +narrowest_signed_type (tree value, unsigned int flags) { enum integer_type_kind itk; @@ -536,16 +475,13 @@ narrowest_signed_type (unsigned HOST_WIDE_INT low, else itk = itk_long_long; + /* int_fits_type_p must think the type of its first argument is + wider than its second argument, or it won't do the proper check. */ + TREE_TYPE (value) = widest_unsigned_literal_type_node; for (; itk < itk_none; itk += 2 /* skip signed types */) - { - tree upper = TYPE_MAX_VALUE (integer_types[itk]); - - if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) > high - || ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) == high - && TREE_INT_CST_LOW (upper) >= low)) - return itk; - } + if (int_fits_type_p (value, integer_types[itk])) + return itk; return itk_none; } @@ -561,19 +497,18 @@ interpret_integer (const cpp_token *token, unsigned int flags) integer = cpp_interpret_integer (parse_in, token, flags); integer = cpp_num_sign_extend (integer, options->precision); + value = build_int_2_wide (integer.low, integer.high); /* The type of a constant with a U suffix is straightforward. */ if (flags & CPP_N_UNSIGNED) - itk = narrowest_unsigned_type (integer.low, integer.high, flags); + itk = narrowest_unsigned_type (value, flags); else { /* The type of a potentially-signed integer constant varies depending on the base it's in, the standard in use, and the length suffixes. */ - enum integer_type_kind itk_u - = narrowest_unsigned_type (integer.low, integer.high, flags); - enum integer_type_kind itk_s - = narrowest_signed_type (integer.low, integer.high, flags); + enum integer_type_kind itk_u = narrowest_unsigned_type (value, flags); + enum integer_type_kind itk_s = narrowest_signed_type (value, flags); /* In both C89 and C99, octal and hex constants may be signed or unsigned, whichever fits tighter. We do not warn about this @@ -597,11 +532,10 @@ interpret_integer (const cpp_token *token, unsigned int flags) if (itk_u < itk_unsigned_long) itk_u = itk_unsigned_long; itk = itk_u; - warning (0, "this decimal constant is unsigned only in ISO C90"); + warning ("this decimal constant is unsigned only in ISO C90"); } - else - warning (OPT_Wtraditional, - "this decimal constant would be unsigned in ISO C90"); + else if (warn_traditional) + warning ("this decimal constant would be unsigned in ISO C90"); } } } @@ -616,15 +550,15 @@ interpret_integer (const cpp_token *token, unsigned int flags) if (itk > itk_unsigned_long && (flags & CPP_N_WIDTH) != CPP_N_LARGE - && !in_system_header && !flag_isoc99) - pedwarn ("integer constant is too large for %qs type", + && ! in_system_header && ! flag_isoc99) + pedwarn ("integer constant is too large for \"%s\" type", (flags & CPP_N_UNSIGNED) ? "unsigned long" : "long"); - value = build_int_cst_wide (type, integer.low, integer.high); + TREE_TYPE (value) = type; /* Convert imaginary to a complex type. */ if (flags & CPP_N_IMAGINARY) - value = build_complex (NULL_TREE, build_int_cst (type, 0), value); + value = build_complex (NULL_TREE, convert (type, integer_zero_node), value); return value; } @@ -639,53 +573,51 @@ interpret_float (const cpp_token *token, unsigned int flags) REAL_VALUE_TYPE real; char *copy; size_t copylen; + const char *typename; - /* Decode type based on width and properties. */ - if (flags & CPP_N_DFLOAT) - if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) - type = dfloat128_type_node; - else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) - type = dfloat32_type_node; - else - type = dfloat64_type_node; - else - if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) + /* FIXME: make %T work in error/warning, then we don't need typename. */ + if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) + { type = long_double_type_node; - else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL - || flag_single_precision_constant) + typename = "long double"; + } + else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL + || flag_single_precision_constant) + { type = float_type_node; - else + typename = "float"; + } + else + { type = double_type_node; + typename = "double"; + } /* Copy the constant to a nul-terminated buffer. If the constant has any suffixes, cut them off; REAL_VALUE_ATOF/ REAL_VALUE_HTOF can't handle them. */ copylen = token->val.str.len; - if (flags & CPP_N_DFLOAT) - copylen -= 2; - else - { - if ((flags & CPP_N_WIDTH) != CPP_N_MEDIUM) - /* Must be an F or L suffix. */ - copylen--; - if (flags & CPP_N_IMAGINARY) - /* I or J suffix. */ - copylen--; - } + if ((flags & CPP_N_WIDTH) != CPP_N_MEDIUM) + /* Must be an F or L suffix. */ + copylen--; + if (flags & CPP_N_IMAGINARY) + /* I or J suffix. */ + copylen--; - copy = (char *) alloca (copylen + 1); + copy = alloca (copylen + 1); memcpy (copy, token->val.str.text, copylen); copy[copylen] = '\0'; - real_from_string3 (&real, copy, TYPE_MODE (type)); + real_from_string (&real, copy); + real_convert (&real, TYPE_MODE (type), &real); - /* Both C and C++ require a diagnostic for a floating constant - outside the range of representable values of its type. Since we - have __builtin_inf* to produce an infinity, it might now be - appropriate for this to be a mandatory pedwarn rather than - conditioned on -pedantic. */ + /* A diagnostic is required for "soft" overflow by some ISO C + testsuites. This is not pedwarn, because some people don't want + an error for this. + ??? That's a dubious reason... is this a mandatory diagnostic or + isn't it? -- zw, 2001-08-21. */ if (REAL_VALUE_ISINF (real) && pedantic) - pedwarn ("floating constant exceeds range of %qT", type); + warning ("floating constant exceeds range of \"%s\"", typename); /* Create a node with determined type and value. */ value = build_real (type, real); @@ -716,7 +648,7 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string) { tree value; bool wide = false; - size_t concats = 0; + size_t count = 1; struct obstack str_ob; cpp_string istr; @@ -728,76 +660,45 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string) if (tok->type == CPP_WSTRING) wide = true; - retry: - tok = cpp_get_token (parse_in); - switch (tok->type) + tok = get_nonpadding_token (); + if (c_dialect_objc () && tok->type == CPP_ATSIGN) { - case CPP_PADDING: - goto retry; - case CPP_ATSIGN: - if (c_dialect_objc ()) - { - objc_string = true; - goto retry; - } - /* FALLTHROUGH */ - - default: - break; - - case CPP_WSTRING: - wide = true; - /* FALLTHROUGH */ + objc_string = true; + tok = get_nonpadding_token (); + } + if (tok->type == CPP_STRING || tok->type == CPP_WSTRING) + { + gcc_obstack_init (&str_ob); + obstack_grow (&str_ob, &str, sizeof (cpp_string)); - case CPP_STRING: - if (!concats) + do { - gcc_obstack_init (&str_ob); - obstack_grow (&str_ob, &str, sizeof (cpp_string)); + count++; + if (tok->type == CPP_WSTRING) + wide = true; + obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string)); + + tok = get_nonpadding_token (); + if (c_dialect_objc () && tok->type == CPP_ATSIGN) + { + objc_string = true; + tok = get_nonpadding_token (); + } } - - concats++; - obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string)); - goto retry; + while (tok->type == CPP_STRING || tok->type == CPP_WSTRING); + strs = obstack_finish (&str_ob); } /* We have read one more token than we want. */ _cpp_backup_tokens (parse_in, 1); - if (concats) - strs = XOBFINISH (&str_ob, cpp_string *); - if (concats && !objc_string && !in_system_header) - warning (OPT_Wtraditional, - "traditional C rejects string constant concatenation"); + if (count > 1 && !objc_string && warn_traditional && !in_system_header) + warning ("traditional C rejects string constant concatenation"); - if ((c_lex_string_translate - ? cpp_interpret_string : cpp_interpret_string_notranslate) - (parse_in, strs, concats + 1, &istr, wide)) + if (cpp_interpret_string (parse_in, strs, count, &istr, wide)) { - value = build_string (istr.len, (char *) istr.text); - free ((void *) istr.text); - - if (c_lex_string_translate == -1) - { - int xlated = cpp_interpret_string_notranslate (parse_in, strs, - concats + 1, - &istr, wide); - /* Assume that, if we managed to translate the string above, - then the untranslated parsing will always succeed. */ - gcc_assert (xlated); - - if (TREE_STRING_LENGTH (value) != (int) istr.len - || 0 != strncmp (TREE_STRING_POINTER (value), (char *) istr.text, - istr.len)) - { - /* Arrange for us to return the untranslated string in - *valp, but to set up the C type of the translated - one. */ - *valp = build_string (istr.len, (char *) istr.text); - valp = &TREE_CHAIN (*valp); - } - free ((void *) istr.text); - } + value = build_string (istr.len, (char *)istr.text); + free ((void *)istr.text); } else { @@ -816,7 +717,7 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string) TREE_TYPE (value) = wide ? wchar_array_type_node : char_array_type_node; *valp = fix_string_type (value); - if (concats) + if (strs != &str) obstack_free (&str_ob, 0); return objc_string ? CPP_OBJC_STRING : wide ? CPP_WSTRING : CPP_STRING; @@ -834,6 +735,13 @@ lex_charconst (const cpp_token *token) result = cpp_interpret_charconst (parse_in, token, &chars_seen, &unsignedp); + /* Cast to cppchar_signed_t to get correct sign-extension of RESULT + before possibly widening to HOST_WIDE_INT for build_int_2. */ + if (unsignedp || (cppchar_signed_t) result >= 0) + value = build_int_2 (result, 0); + else + value = build_int_2 ((cppchar_signed_t) result, -1); + if (token->type == CPP_WCHAR) type = wchar_type_node; /* In C, a character constant has type 'int'. @@ -843,12 +751,6 @@ lex_charconst (const cpp_token *token) else type = char_type_node; - /* Cast to cppchar_signed_t to get correct sign-extension of RESULT - before possibly widening to HOST_WIDE_INT for build_int_cst. */ - if (unsignedp || (cppchar_signed_t) result >= 0) - value = build_int_cst_wide (type, result, 0); - else - value = build_int_cst_wide (type, (cppchar_signed_t) result, -1); - + TREE_TYPE (value) = type; return value; } diff --git a/contrib/gcc/c-opts.c b/contrib/gcc/c-opts.c index ed04791..84f86cb 100644 --- a/contrib/gcc/c-opts.c +++ b/contrib/gcc/c-opts.c @@ -1,6 +1,5 @@ /* C/ObjC/C++ command line option handling. - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Neil Booth. This file is part of GCC. @@ -17,8 +16,10 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* $FreeBSD$ */ #include "config.h" #include "system.h" @@ -38,7 +39,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "debug.h" /* For debug_hooks. */ #include "opts.h" #include "options.h" -#include "mkdeps.h" #ifndef DOLLARS_IN_IDENTIFIERS # define DOLLARS_IN_IDENTIFIERS true @@ -48,9 +48,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA # define TARGET_SYSTEM_ROOT NULL #endif -#ifndef TARGET_OPTF -#define TARGET_OPTF(ARG) -#endif +static int saved_lineno; /* CPP's options. */ static cpp_options *cpp_opts; @@ -71,18 +69,12 @@ static bool deps_seen; /* If -v seen. */ static bool verbose; -/* If -lang-fortran seen. */ -static bool lang_fortran = false; - /* Dependency output file. */ static const char *deps_file; /* The prefix given by -iprefix, if any. */ static const char *iprefix; -/* The multilib directory given by -imultilib, if any. */ -static const char *imultilib; - /* The system root, if any. Overridden by -isysroot. */ static const char *sysroot = TARGET_SYSTEM_ROOT; @@ -98,15 +90,15 @@ static bool quote_chain_split; /* If -Wunused-macros. */ static bool warn_unused_macros; -/* If -Wvariadic-macros. */ -static bool warn_variadic_macros = true; - /* Number of deferred options. */ static size_t deferred_count; /* Number of deferred options scanned for -include. */ static size_t include_cursor; +/* Permit Fotran front-end options. */ +static bool permit_fortran_options; + static void set_Wimplicit (int); static void handle_OPT_d (const char *); static void set_std_cxx98 (int); @@ -148,25 +140,23 @@ c_common_missing_argument (const char *opt, size_t code) return false; case OPT_fconstant_string_class_: - error ("no class name specified with %qs", opt); + error ("no class name specified with \"%s\"", opt); break; case OPT_A: - error ("assertion missing after %qs", opt); + error ("assertion missing after \"%s\"", opt); break; case OPT_D: case OPT_U: - error ("macro name missing after %qs", opt); + error ("macro name missing after \"%s\"", opt); break; - case OPT_F: case OPT_I: case OPT_idirafter: case OPT_isysroot: case OPT_isystem: - case OPT_iquote: - error ("missing path after %qs", opt); + error ("missing path after \"%s\"", opt); break; case OPT_MF: @@ -175,12 +165,12 @@ c_common_missing_argument (const char *opt, size_t code) case OPT_include: case OPT_imacros: case OPT_o: - error ("missing filename after %qs", opt); + error ("missing filename after \"%s\"", opt); break; case OPT_MQ: case OPT_MT: - error ("missing makefile target after %qs", opt); + error ("missing makefile target after \"%s\"", opt); break; } @@ -216,7 +206,7 @@ c_common_init_options (unsigned int argc, const char **argv) } parse_in = cpp_create_reader (c_dialect_cxx () ? CLK_GNUCXX: CLK_GNUC89, - ident_hash, &line_table); + ident_hash); cpp_opts = cpp_get_options (parse_in); cpp_opts->dollars_in_ident = DOLLARS_IN_IDENTIFIERS; @@ -226,35 +216,33 @@ c_common_init_options (unsigned int argc, const char **argv) before passing on command-line options to cpplib. */ cpp_opts->warn_dollars = 0; + flag_const_strings = c_dialect_cxx (); flag_exceptions = c_dialect_cxx (); warn_pointer_arith = c_dialect_cxx (); - warn_write_strings = c_dialect_cxx(); - deferred_opts = XNEWVEC (struct deferred_opt, argc); + deferred_opts = xmalloc (argc * sizeof (struct deferred_opt)); result = lang_flags[c_language]; if (c_language == clk_c) { - /* If preprocessing assembly language, accept any of the C-family - front end options since the driver may pass them through. */ for (i = 1; i < argc; i++) - if (! strcmp (argv[i], "-lang-asm")) - { - result |= CL_C | CL_ObjC | CL_CXX | CL_ObjCXX; - break; - } - -#ifdef CL_Fortran - for (i = 1; i < argc; i++) - if (! strcmp (argv[i], "-lang-fortran")) { - result |= CL_Fortran; - break; - } + /* If preprocessing assembly language, accept any of the C-family + front end options since the driver may pass them through. */ + if (! strcmp (argv[i], "-lang-asm")) + result |= CL_C | CL_ObjC | CL_CXX | CL_ObjCXX; +#ifdef CL_F77 + /* If potentially preprocessing Fortran we have to accept its + front end options since the driver may them through. */ + else if (! strcmp (argv[i], "-traditional-cpp")) + { + permit_fortran_options = true; + result |= CL_F77; + } #endif + } } - return result; } @@ -269,20 +257,10 @@ c_common_handle_option (size_t scode, const char *arg, int value) enum opt_code code = (enum opt_code) scode; int result = 1; - /* Prevent resetting the language standard to a C dialect when the driver - has already determined that we're looking at assembler input. */ - bool preprocessing_asm_p = (cpp_get_options (parse_in)->lang == CLK_ASM); - switch (code) { default: - if (cl_options[code].flags & (CL_C | CL_CXX | CL_ObjC | CL_ObjCXX)) - break; -#ifdef CL_Fortran - if (lang_fortran && (cl_options[code].flags & (CL_Fortran))) - break; -#endif - result = 0; + result = permit_fortran_options; break; case OPT__output_pch_: @@ -314,20 +292,15 @@ c_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->print_include_names = 1; break; - case OPT_F: - TARGET_OPTF (xstrdup (arg)); - break; - case OPT_I: if (strcmp (arg, "-")) - add_path (xstrdup (arg), BRACKET, 0, true); + add_path (xstrdup (arg), BRACKET, 0); else { if (quote_chain_split) error ("-I- specified twice"); quote_chain_split = true; split_quote_chain (); - inform ("obsolete option -I- used, please use -iquote instead"); } break; @@ -381,6 +354,10 @@ c_common_handle_option (size_t scode, const char *arg, int value) defer_opt (code, arg); break; + case OPT_Wabi: + warn_abi = value; + break; + case OPT_Wall: set_Wunused (value); set_Wformat (value); @@ -394,8 +371,6 @@ c_common_handle_option (size_t scode, const char *arg, int value) warn_sign_compare = value; warn_switch = value; warn_strict_aliasing = value; - warn_strict_overflow = value; - warn_address = value; /* Only warn about unknown pragmas that are not in system headers. */ @@ -414,6 +389,7 @@ c_common_handle_option (size_t scode, const char *arg, int value) else { /* C++-specific warnings. */ + warn_nonvdtor = value; warn_reorder = value; warn_nontemplate_friend = value; } @@ -422,9 +398,18 @@ c_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->warn_comments = value; cpp_opts->warn_num_sign_change = value; cpp_opts->warn_multichar = value; /* Was C++ only. */ + break; - if (warn_pointer_sign == -1) - warn_pointer_sign = 1; + case OPT_Wbad_function_cast: + warn_bad_function_cast = value; + break; + + case OPT_Wcast_qual: + warn_cast_qual = value; + break; + + case OPT_Wchar_subscripts: + warn_char_subscripts = value; break; case OPT_Wcomment: @@ -432,23 +417,47 @@ c_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->warn_comments = value; break; + case OPT_Wconversion: + warn_conversion = value; + break; + + case OPT_Wctor_dtor_privacy: + warn_ctor_dtor_privacy = value; + break; + + case OPT_Wdeclaration_after_statement: + warn_declaration_after_statement = value; + break; + case OPT_Wdeprecated: + warn_deprecated = value; cpp_opts->warn_deprecated = value; break; + case OPT_Wdiv_by_zero: + warn_div_by_zero = value; + break; + + case OPT_Weffc__: + warn_ecpp = value; + break; + case OPT_Wendif_labels: cpp_opts->warn_endif_labels = value; break; case OPT_Werror: cpp_opts->warnings_are_errors = value; - global_dc->warning_as_error_requested = value; break; case OPT_Werror_implicit_function_declaration: mesg_implicit_function_declaration = 2; break; + case OPT_Wfloat_equal: + warn_float_equal = value; + break; + case OPT_Wformat: set_Wformat (value); break; @@ -457,18 +466,58 @@ c_common_handle_option (size_t scode, const char *arg, int value) set_Wformat (atoi (arg)); break; + case OPT_Wformat_extra_args: + warn_format_extra_args = value; + break; + + case OPT_Wformat_nonliteral: + warn_format_nonliteral = value; + break; + + case OPT_Wformat_security: + warn_format_security = value; + break; + + case OPT_Wformat_y2k: + warn_format_y2k = value; + break; + + case OPT_Wformat_zero_length: + warn_format_zero_length = value; + break; + + case OPT_Winit_self: + warn_init_self = value; + break; + case OPT_Wimplicit: set_Wimplicit (value); break; + case OPT_Wimplicit_function_declaration: + mesg_implicit_function_declaration = value; + break; + + case OPT_Wimplicit_int: + warn_implicit_int = value; + break; + case OPT_Wimport: /* Silently ignore for now. */ break; + case OPT_Winvalid_offsetof: + warn_invalid_offsetof = value; + break; + case OPT_Winvalid_pch: cpp_opts->warn_invalid_pch = value; break; + case OPT_Wlong_long: + warn_long_long = value; + break; + case OPT_Wmain: if (value) warn_main = 1; @@ -476,33 +525,104 @@ c_common_handle_option (size_t scode, const char *arg, int value) warn_main = -1; break; - case OPT_Wmissing_include_dirs: - cpp_opts->warn_missing_include_dirs = value; + case OPT_Wmissing_braces: + warn_missing_braces = value; + break; + + case OPT_Wmissing_declarations: + warn_missing_declarations = value; + break; + + case OPT_Wmissing_format_attribute: + warn_missing_format_attribute = value; + break; + + case OPT_Wmissing_prototypes: + warn_missing_prototypes = value; break; case OPT_Wmultichar: cpp_opts->warn_multichar = value; break; - case OPT_Wnormalized_: - if (!value || (arg && strcasecmp (arg, "none") == 0)) - cpp_opts->warn_normalize = normalized_none; - else if (!arg || strcasecmp (arg, "nfkc") == 0) - cpp_opts->warn_normalize = normalized_KC; - else if (strcasecmp (arg, "id") == 0) - cpp_opts->warn_normalize = normalized_identifier_C; - else if (strcasecmp (arg, "nfc") == 0) - cpp_opts->warn_normalize = normalized_C; - else - error ("argument %qs to %<-Wnormalized%> not recognized", arg); + case OPT_Wnested_externs: + warn_nested_externs = value; + break; + + case OPT_Wnon_template_friend: + warn_nontemplate_friend = value; + break; + + case OPT_Wnon_virtual_dtor: + warn_nonvdtor = value; + break; + + case OPT_Wnonnull: + warn_nonnull = value; + break; + + case OPT_Wold_style_definition: + warn_old_style_definition = value; + break; + + case OPT_Wold_style_cast: + warn_old_style_cast = value; + break; + + case OPT_Woverloaded_virtual: + warn_overloaded_virtual = value; + break; + + case OPT_Wparentheses: + warn_parentheses = value; + break; + + case OPT_Wpmf_conversions: + warn_pmf2ptr = value; + break; + + case OPT_Wpointer_arith: + warn_pointer_arith = value; + break; + + case OPT_Wprotocol: + warn_protocol = value; + break; + + case OPT_Wselector: + warn_selector = value; + break; + + case OPT_Wredundant_decls: + warn_redundant_decls = value; + break; + + case OPT_Wreorder: + warn_reorder = value; break; case OPT_Wreturn_type: warn_return_type = value; break; - case OPT_Wstrict_null_sentinel: - warn_strict_null_sentinel = value; + case OPT_Wsequence_point: + warn_sequence_point = value; + break; + + case OPT_Wsign_compare: + warn_sign_compare = value; + break; + + case OPT_Wsign_promo: + warn_sign_promo = value; + break; + + case OPT_Wstrict_prototypes: + warn_strict_prototypes = value; + break; + + case OPT_Wsynth: + warn_synth = value; break; case OPT_Wsystem_headers: @@ -510,6 +630,7 @@ c_common_handle_option (size_t scode, const char *arg, int value) break; case OPT_Wtraditional: + warn_traditional = value; cpp_opts->warn_traditional = value; break; @@ -517,6 +638,10 @@ c_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->warn_trigraphs = value; break; + case OPT_Wundeclared_selector: + warn_undeclared_selector = value; + break; + case OPT_Wundef: cpp_opts->warn_undef = value; break; @@ -531,18 +656,11 @@ c_common_handle_option (size_t scode, const char *arg, int value) warn_unused_macros = value; break; - case OPT_Wvariadic_macros: - warn_variadic_macros = value; - break; - case OPT_Wwrite_strings: - warn_write_strings = value; - break; - - case OPT_Weffc__: - warn_ecpp = value; - if (value) - warn_nonvdtor = true; + if (!c_dialect_cxx ()) + flag_const_strings = value; + else + warn_write_strings = value; break; case OPT_ansi: @@ -581,7 +699,7 @@ c_common_handle_option (size_t scode, const char *arg, int value) case OPT_fvtable_thunks: case OPT_fxref: case OPT_fvtable_gc: - warning (0, "switch %qs is no longer supported", option->opt_text); + warning ("switch \"%s\" is no longer supported", option->opt_text); break; case OPT_faccess_control: @@ -607,6 +725,11 @@ c_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->dollars_in_ident = value; break; + case OPT_fdump_: + if (!dump_switch_p (arg)) + result = 0; + break; + case OPT_ffreestanding: value = !value; /* Fall through.... */ @@ -632,6 +755,7 @@ c_common_handle_option (size_t scode, const char *arg, int value) case OPT_fsigned_bitfields: flag_signed_bitfields = value; + explicit_flag_signed_bitfields = 1; break; case OPT_fsigned_char: @@ -640,6 +764,7 @@ c_common_handle_option (size_t scode, const char *arg, int value) case OPT_funsigned_bitfields: flag_signed_bitfields = !value; + explicit_flag_signed_bitfields = 1; break; case OPT_funsigned_char: @@ -654,6 +779,10 @@ c_common_handle_option (size_t scode, const char *arg, int value) flag_conserve_space = value; break; + case OPT_fconst_strings: + flag_const_strings = value; + break; + case OPT_fconstant_string_class_: constant_string_class_name = arg; break; @@ -670,8 +799,11 @@ c_common_handle_option (size_t scode, const char *arg, int value) flag_enforce_eh_specs = value; break; - case OPT_fextended_identifiers: - cpp_opts->extended_identifiers = value; + case OPT_ffixed_form: + case OPT_ffixed_line_length_: + /* Fortran front end options ignored when preprocessing only. */ + if (!flag_preprocess_only) + result = 0; break; case OPT_ffor_scope: @@ -687,7 +819,7 @@ c_common_handle_option (size_t scode, const char *arg, int value) break; case OPT_fhandle_exceptions: - warning (0, "-fhandle-exceptions has been renamed -fexceptions (and is now on by default)"); + warning ("-fhandle-exceptions has been renamed -fexceptions (and is now on by default)"); flag_exceptions = value; break; @@ -719,6 +851,10 @@ c_common_handle_option (size_t scode, const char *arg, int value) flag_no_nonansi_builtin = !value; break; + case OPT_fobjc_exceptions: + flag_objc_exceptions = value; + break; + case OPT_foperator_names: cpp_opts->operator_names = value; break; @@ -731,10 +867,6 @@ c_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->restore_pch_deps = value; break; - case OPT_fpch_preprocess: - flag_pch_preprocess = value; - break; - case OPT_fpermissive: flag_permissive = value; break; @@ -746,7 +878,7 @@ c_common_handle_option (size_t scode, const char *arg, int value) case OPT_freplace_objc_classes: flag_replace_objc_classes = value; break; - + case OPT_frepo: flag_use_repository = value; if (value) @@ -790,23 +922,11 @@ c_common_handle_option (size_t scode, const char *arg, int value) case OPT_fuse_cxa_atexit: flag_use_cxa_atexit = value; break; - - case OPT_fuse_cxa_get_exception_ptr: - flag_use_cxa_get_exception_ptr = value; - break; - - case OPT_fvisibility_inlines_hidden: - visibility_options.inlines_hidden = value; - break; case OPT_fweak: flag_weak = value; break; - case OPT_fthreadsafe_statics: - flag_threadsafe_statics = value; - break; - case OPT_fzero_link: flag_zero_link = value; break; @@ -816,7 +936,7 @@ c_common_handle_option (size_t scode, const char *arg, int value) break; case OPT_idirafter: - add_path (xstrdup (arg), AFTER, 0, true); + add_path (xstrdup (arg), AFTER, 0); break; case OPT_imacros: @@ -824,24 +944,16 @@ c_common_handle_option (size_t scode, const char *arg, int value) defer_opt (code, arg); break; - case OPT_imultilib: - imultilib = arg; - break; - case OPT_iprefix: iprefix = arg; break; - case OPT_iquote: - add_path (xstrdup (arg), QUOTE, 0, true); - break; - case OPT_isysroot: sysroot = arg; break; case OPT_isystem: - add_path (xstrdup (arg), SYSTEM, 0, true); + add_path (xstrdup (arg), SYSTEM, 0); break; case OPT_iwithprefix: @@ -857,10 +969,6 @@ c_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->dollars_in_ident = false; break; - case OPT_lang_fortran: - lang_fortran = true; - break; - case OPT_lang_objc: cpp_opts->objc = 1; break; @@ -889,55 +997,41 @@ c_common_handle_option (size_t scode, const char *arg, int value) case OPT_pedantic: cpp_opts->pedantic = 1; cpp_opts->warn_endif_labels = 1; - if (warn_pointer_sign == -1) - warn_pointer_sign = 1; - if (warn_overlength_strings == -1) - warn_overlength_strings = 1; break; case OPT_print_objc_runtime_info: print_struct_values = 1; break; - case OPT_print_pch_checksum: - c_common_print_pch_checksum (stdout); - exit_after_options = true; - break; - case OPT_remap: cpp_opts->remap = 1; break; case OPT_std_c__98: case OPT_std_gnu__98: - if (!preprocessing_asm_p) - set_std_cxx98 (code == OPT_std_c__98 /* ISO */); + set_std_cxx98 (code == OPT_std_c__98 /* ISO */); break; case OPT_std_c89: case OPT_std_iso9899_1990: case OPT_std_iso9899_199409: - if (!preprocessing_asm_p) - set_std_c89 (code == OPT_std_iso9899_199409 /* c94 */, true /* ISO */); + set_std_c89 (code == OPT_std_iso9899_199409 /* c94 */, true /* ISO */); break; case OPT_std_gnu89: - if (!preprocessing_asm_p) - set_std_c89 (false /* c94 */, false /* ISO */); + set_std_c89 (false /* c94 */, false /* ISO */); break; case OPT_std_c99: case OPT_std_c9x: case OPT_std_iso9899_1999: case OPT_std_iso9899_199x: - if (!preprocessing_asm_p) - set_std_c99 (true /* ISO */); + set_std_c99 (true /* ISO */); break; case OPT_std_gnu99: case OPT_std_gnu9x: - if (!preprocessing_asm_p) - set_std_c99 (false /* ISO */); + set_std_c99 (false /* ISO */); break; case OPT_trigraphs: @@ -959,6 +1053,9 @@ c_common_handle_option (size_t scode, const char *arg, int value) case OPT_v: verbose = true; break; + + case OPT_fformat_extensions: + break; } return result; @@ -973,7 +1070,7 @@ c_common_post_options (const char **pfilename) /* Canonicalize the input and output filenames. */ if (in_fnames == NULL) { - in_fnames = XNEWVEC (const char *, 1); + in_fnames = xmalloc (sizeof (in_fnames[0])); in_fnames[0] = ""; } else if (strcmp (in_fnames[0], "-") == 0) @@ -989,80 +1086,48 @@ c_common_post_options (const char **pfilename) sanitize_cpp_opts (); - register_include_chains (parse_in, sysroot, iprefix, imultilib, + register_include_chains (parse_in, sysroot, iprefix, std_inc, std_cxx_inc && c_dialect_cxx (), verbose); -#ifdef C_COMMON_OVERRIDE_OPTIONS - /* Some machines may reject certain combinations of C - language-specific options. */ - C_COMMON_OVERRIDE_OPTIONS; -#endif - flag_inline_trees = 1; - /* Use tree inlining. */ - if (!flag_no_inline) - flag_no_inline = 1; - if (flag_inline_functions) - flag_inline_trees = 2; - - /* We recognize -fgnu89-inline in preparation for 4.3 where the - option will be meaningful. Here we just reject - -fno-gnu89-inline, since we don't support it. */ - if (!flag_gnu89_inline) - error ("-fno-gnu89-inline is not supported"); - - /* If we are given more than one input file, we must use - unit-at-a-time mode. */ - if (num_in_fnames > 1) - flag_unit_at_a_time = 1; - - /* Default to ObjC sjlj exception handling if NeXT runtime. */ - if (flag_objc_sjlj_exceptions < 0) - flag_objc_sjlj_exceptions = flag_next_runtime; - if (flag_objc_exceptions && !flag_objc_sjlj_exceptions) - flag_exceptions = 1; - - /* -Wextra implies -Wsign-compare, -Wmissing-field-initializers and - -Woverride-init, but not if explicitly overridden. */ + /* Use tree inlining if possible. Function instrumentation is only + done in the RTL level, so we disable tree inlining. */ + if (flag_instrument_function_entry_exit) + { + flag_no_inline = 1; + flag_really_no_inline = 1; + } + else + { + if (!flag_no_inline) + flag_no_inline = 1; + if (flag_inline_functions) + { + flag_inline_trees = 2; + flag_inline_functions = 0; + } + } + + /* -Wextra implies -Wsign-compare, but not if explicitly + overridden. */ if (warn_sign_compare == -1) warn_sign_compare = extra_warnings; - if (warn_missing_field_initializers == -1) - warn_missing_field_initializers = extra_warnings; - if (warn_override_init == -1) - warn_override_init = extra_warnings; - - /* -Wpointer_sign is disabled by default, but it is enabled if any - of -Wall or -pedantic are given. */ - if (warn_pointer_sign == -1) - warn_pointer_sign = 0; - - /* -Woverlength-strings is off by default, but is enabled by -pedantic. - It is never enabled in C++, as the minimum limit is not normative - in that standard. */ - if (warn_overlength_strings == -1 || c_dialect_cxx ()) - warn_overlength_strings = 0; /* Special format checking options don't work without -Wformat; warn if they are used. */ - if (!warn_format) - { - warning (OPT_Wformat_y2k, - "-Wformat-y2k ignored without -Wformat"); - warning (OPT_Wformat_extra_args, - "-Wformat-extra-args ignored without -Wformat"); - warning (OPT_Wformat_zero_length, - "-Wformat-zero-length ignored without -Wformat"); - warning (OPT_Wformat_nonliteral, - "-Wformat-nonliteral ignored without -Wformat"); - warning (OPT_Wformat_security, - "-Wformat-security ignored without -Wformat"); - } - - /* C99 requires special handling of complex multiplication and division; - -ffast-math and -fcx-limited-range are handled in process_options. */ - if (flag_isoc99) - flag_complex_method = 2; + if (warn_format_y2k && !warn_format) + warning ("-Wformat-y2k ignored without -Wformat"); + if (warn_format_extra_args && !warn_format) + warning ("-Wformat-extra-args ignored without -Wformat"); + if (warn_format_zero_length && !warn_format) + warning ("-Wformat-zero-length ignored without -Wformat"); + if (warn_format_nonliteral && !warn_format) + warning ("-Wformat-nonliteral ignored without -Wformat"); + if (warn_format_security && !warn_format) + warning ("-Wformat-security ignored without -Wformat"); + if (warn_missing_format_attribute && !warn_format) + warning ("-Wmissing-format-attribute ignored without -Wformat"); if (flag_preprocess_only) { @@ -1091,7 +1156,7 @@ c_common_post_options (const char **pfilename) init_c_lex (); /* Yuk. WTF is this? I do know ObjC relies on it somewhere. */ - input_location = UNKNOWN_LOCATION; + input_line = 0; } cb = cpp_get_callbacks (parse_in); @@ -1099,7 +1164,8 @@ c_common_post_options (const char **pfilename) cb->dir_change = cb_dir_change; cpp_post_options (parse_in); - input_location = UNKNOWN_LOCATION; + saved_lineno = input_line; + input_line = 0; /* If an error has occurred in cpplib, note it so we fail immediately. */ @@ -1115,7 +1181,7 @@ c_common_post_options (const char **pfilename) } if (flag_working_directory - && flag_preprocess_only && !flag_no_line_commands) + && flag_preprocess_only && ! flag_no_line_commands) pp_dir_change (parse_in, get_src_pwd ()); return flag_preprocess_only; @@ -1125,22 +1191,21 @@ c_common_post_options (const char **pfilename) bool c_common_init (void) { + input_line = saved_lineno; + /* Set up preprocessor arithmetic. Must be done after call to c_common_nodes_and_builtins for type nodes to be good. */ cpp_opts->precision = TYPE_PRECISION (intmax_type_node); cpp_opts->char_precision = TYPE_PRECISION (char_type_node); cpp_opts->int_precision = TYPE_PRECISION (integer_type_node); cpp_opts->wchar_precision = TYPE_PRECISION (wchar_type_node); - cpp_opts->unsigned_wchar = TYPE_UNSIGNED (wchar_type_node); + cpp_opts->unsigned_wchar = TREE_UNSIGNED (wchar_type_node); cpp_opts->bytes_big_endian = BYTES_BIG_ENDIAN; /* This can't happen until after wchar_precision and bytes_big_endian are known. */ cpp_init_iconv (parse_in); - if (version_flag) - c_common_print_pch_checksum (stderr); - if (flag_preprocess_only) { finish_options (); @@ -1157,44 +1222,41 @@ c_common_init (void) /* Initialize the integrated preprocessor after debug output has been initialized; loop over each input file. */ void -c_common_parse_file (int set_yydebug) +c_common_parse_file (int set_yydebug ATTRIBUTE_UNUSED) { - unsigned int i; - - /* Enable parser debugging, if requested and we can. If requested - and we can't, notify the user. */ + unsigned file_index; + #if YYDEBUG != 0 yydebug = set_yydebug; #else - if (set_yydebug) - warning (0, "YYDEBUG was not defined at build time, -dy ignored"); + warning ("YYDEBUG not defined"); #endif - i = 0; - for (;;) + file_index = 0; + + do { - /* Start the main input file, if the debug writer wants it. */ - if (debug_hooks->start_end_main_source_file) - (*debug_hooks->start_source_file) (0, this_input_filename); + if (file_index > 0) + { + /* Reset the state of the parser. */ + c_reset_state(); + + /* Reset cpplib's macros and start a new file. */ + cpp_undef_all (parse_in); + main_input_filename = this_input_filename + = cpp_read_main_file (parse_in, in_fnames[file_index]); + if (this_input_filename == NULL) + break; + } finish_options (); - pch_init (); - push_file_scope (); + if (file_index == 0) + pch_init(); c_parse_file (); - finish_file (); - pop_file_scope (); - /* And end the main input file, if the debug writer wants it */ - if (debug_hooks->start_end_main_source_file) - (*debug_hooks->end_source_file) (0); - if (++i >= num_in_fnames) - break; - cpp_undef_all (parse_in); - this_input_filename - = cpp_read_main_file (parse_in, in_fnames[i]); - /* If an input file is missing, abandon further compilation. - cpplib has issued a diagnostic. */ - if (!this_input_filename) - break; - } + + file_index++; + } while (file_index < num_in_fnames); + + finish_file (); } /* Common finish hook for the C, ObjC and C++ front ends. */ @@ -1270,7 +1332,6 @@ check_deps_environment_vars (void) deps_file = spec; deps_append = 1; - deps_seen = true; } } @@ -1279,22 +1340,13 @@ static void handle_deferred_opts (void) { size_t i; - struct deps *deps; - - /* Avoid allocating the deps buffer if we don't need it. - (This flag may be true without there having been -MT or -MQ - options, but we'll still need the deps buffer.) */ - if (!deps_seen) - return; - - deps = cpp_get_deps (parse_in); for (i = 0; i < deferred_count; i++) { struct deferred_opt *opt = &deferred_opts[i]; if (opt->code == OPT_MT || opt->code == OPT_MQ) - deps_add_target (deps, opt->arg, opt->code == OPT_MQ); + cpp_add_dependency_target (parse_in, opt->arg, opt->code == OPT_MQ); } } @@ -1315,7 +1367,7 @@ sanitize_cpp_opts (void) /* Disable -dD, -dN and -dI if normal output is suppressed. Allow -dM since at least glibc relies on -M -dM to work. */ - /* Also, flag_no_output implies flag_no_line_commands, always. */ + /* Also, flag_no_output implies flag_no_line_commands, always. */ if (flag_no_output) { if (flag_dump_macros != 'M') @@ -1332,11 +1384,6 @@ sanitize_cpp_opts (void) cpp_opts->warn_long_long = warn_long_long && ((!flag_isoc99 && pedantic) || warn_traditional); - /* Similarly with -Wno-variadic-macros. No check for c99 here, since - this also turns off warnings about GCCs extension. */ - cpp_opts->warn_variadic_macros - = warn_variadic_macros && (pedantic || warn_traditional); - /* If we're generating preprocessor output, emit current directory if explicitly requested or if debugging information is enabled. ??? Maybe we should only do it for debugging formats that @@ -1357,12 +1404,12 @@ add_prefixed_path (const char *suffix, size_t chain) prefix = iprefix ? iprefix : cpp_GCC_INCLUDE_DIR; prefix_len = iprefix ? strlen (iprefix) : cpp_GCC_INCLUDE_DIR_len; - path = (char *) xmalloc (prefix_len + suffix_len + 1); + path = xmalloc (prefix_len + suffix_len + 1); memcpy (path, prefix, prefix_len); memcpy (path + prefix_len, suffix, suffix_len); path[prefix_len + suffix_len] = '\0'; - add_path (path, chain, 0, false); + add_path (path, chain, 0); } /* Handle -D, -U, -A, -imacros, and the first -include. */ @@ -1373,10 +1420,7 @@ finish_options (void) { size_t i; - cb_file_change (parse_in, - linemap_add (&line_table, LC_RENAME, 0, - _("<built-in>"), 0)); - + cpp_change_file (parse_in, LC_RENAME, _("<built-in>")); cpp_init_builtins (parse_in, flag_hosted); c_cpp_builtins (parse_in); @@ -1391,10 +1435,7 @@ finish_options (void) their acceptance on the -std= setting. */ cpp_opts->warn_dollars = (cpp_opts->pedantic && !cpp_opts->c99); - cb_file_change (parse_in, - linemap_add (&line_table, LC_RENAME, 0, - _("<command-line>"), 0)); - + cpp_change_file (parse_in, LC_RENAME, _("<command line>")); for (i = 0; i < deferred_count; i++) { struct deferred_opt *opt = &deferred_opts[i]; @@ -1439,7 +1480,7 @@ push_command_line_include (void) { struct deferred_opt *opt = &deferred_opts[include_cursor++]; - if (!cpp_opts->preprocessed && opt->code == OPT_include + if (! cpp_opts->preprocessed && opt->code == OPT_include && cpp_push_include (parse_in, opt->arg)) return; } @@ -1450,18 +1491,19 @@ push_command_line_include (void) /* -Wunused-macros should only warn about macros defined hereafter. */ cpp_opts->warn_unused_macros = warn_unused_macros; /* Restore the line map from <command line>. */ - if (!cpp_opts->preprocessed) - cpp_change_file (parse_in, LC_RENAME, this_input_filename); + if (! cpp_opts->preprocessed) + cpp_change_file (parse_in, LC_RENAME, main_input_filename); /* Set this here so the client can change the option if it wishes, and after stacking the main file so we don't trace the main file. */ - line_table.trace_includes = cpp_opts->print_include_names; + cpp_get_line_maps (parse_in)->trace_includes + = cpp_opts->print_include_names; } } /* File change callback. Has to handle -include files. */ static void -cb_file_change (cpp_reader * ARG_UNUSED (pfile), +cb_file_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const struct line_map *new_map) { if (flag_preprocess_only) @@ -1474,10 +1516,10 @@ cb_file_change (cpp_reader * ARG_UNUSED (pfile), } void -cb_dir_change (cpp_reader * ARG_UNUSED (pfile), const char *dir) +cb_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir) { - if (!set_src_pwd (dir)) - warning (0, "too late for # directive to set debug directory"); + if (! set_src_pwd (dir)) + warning ("too late for # directive to set debug directory"); } /* Set the C 89 standard (with 1994 amendments if C94, without GNU @@ -1492,6 +1534,7 @@ set_std_c89 (int c94, int iso) flag_no_nonansi_builtin = iso; flag_isoc94 = c94; flag_isoc99 = 0; + flag_writable_strings = 0; } /* Set the C 99 standard (without GNU extensions if ISO). */ @@ -1504,6 +1547,7 @@ set_std_c99 (int iso) flag_iso = iso; flag_isoc99 = 1; flag_isoc94 = 1; + flag_writable_strings = 0; } /* Set the C++ 98 standard (without GNU extensions if ISO). */ diff --git a/contrib/gcc/c-tree.h b/contrib/gcc/c-tree.h index 5139215..0500f81 100644 --- a/contrib/gcc/c-tree.h +++ b/contrib/gcc/c-tree.h @@ -1,6 +1,6 @@ /* Definitions for C parsing and type checking. Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -16,28 +16,74 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #ifndef GCC_C_TREE_H #define GCC_C_TREE_H #include "c-common.h" -#include "toplev.h" -#include "diagnostic.h" -/* struct lang_identifier is private to c-decl.c, but langhooks.c needs to - know how big it is. This is sanity-checked in c-decl.c. */ -#define C_SIZEOF_STRUCT_LANG_IDENTIFIER \ - (sizeof (struct c_common_identifier) + 3 * sizeof (void *)) +/* Language-dependent contents of an identifier. */ + +/* The limbo_value is used for block level extern declarations, which need + to be type checked against subsequent extern declarations. They can't + be referenced after they fall out of scope, so they can't be global. + + The rid_code field is used for keywords. It is in all + lang_identifier nodes, because some keywords are only special in a + particular context. */ + +struct lang_identifier GTY(()) +{ + struct c_common_identifier common_id; + tree symbol_value; + tree tag_value; + tree label_value; +}; + +/* The resulting tree type. */ + +union lang_tree_node + GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), + chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE ? (union lang_tree_node *)TYPE_NEXT_VARIANT (&%h.generic) : (union lang_tree_node *)TREE_CHAIN (&%h.generic)"))) +{ + union tree_node GTY ((tag ("0"), + desc ("tree_node_structure (&%h)"))) + generic; + struct lang_identifier GTY ((tag ("1"))) identifier; +}; /* Language-specific declaration information. */ struct lang_decl GTY(()) { - char dummy; + /* The return types and parameter types may have variable size. + This is a list of any SAVE_EXPRs that need to be evaluated to + compute those sizes. */ + tree pending_sizes; }; +/* Macros for access to language-specific slots in an identifier. */ +/* Each of these slots contains a DECL node or null. */ + +/* The value of the identifier in the namespace of "ordinary identifiers" + (data objects, enum constants, functions, typedefs). */ +#define IDENTIFIER_SYMBOL_VALUE(NODE) \ + (((struct lang_identifier *) (NODE))->symbol_value) +/* The value of the identifier in the namespace of struct, union, + and enum tags. */ +#define IDENTIFIER_TAG_VALUE(NODE) \ + (((struct lang_identifier *) (NODE))->tag_value) +/* The value of the identifier in the namespace of labels. */ +#define IDENTIFIER_LABEL_VALUE(NODE) \ + (((struct lang_identifier *) (NODE))->label_value) + +/* In identifiers, C uses the following fields in a special way: + TREE_PUBLIC to record that there was a previous local extern decl. + TREE_USED to record that such a decl was used. + TREE_ADDRESSABLE to record that the address of such a decl was used. */ + /* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is read-only. */ #define C_TYPE_FIELDS_READONLY(TYPE) TREE_LANG_FLAG_1 (TYPE) @@ -57,17 +103,10 @@ struct lang_decl GTY(()) and C_RID_YYCODE is the token number wanted by Yacc. */ #define C_IS_RESERVED_WORD(ID) TREE_LANG_FLAG_0 (ID) +/* In a RECORD_TYPE, a sorted array of the fields of the type. */ struct lang_type GTY(()) { - /* In a RECORD_TYPE, a sorted array of the fields of the type. */ struct sorted_fields_type * GTY ((reorder ("resort_sorted_fields"))) s; - /* In an ENUMERAL_TYPE, the min and max values. */ - tree enum_min; - tree enum_max; - /* In a RECORD_TYPE, information specific to Objective-C, such - as a list of adopted protocols or a pointer to a corresponding - @interface. See objc/objc-act.h for details. */ - tree objc_info; }; /* Record whether a type or decl was written with nonconstant size. @@ -75,6 +114,10 @@ struct lang_type GTY(()) #define C_TYPE_VARIABLE_SIZE(TYPE) TYPE_LANG_FLAG_1 (TYPE) #define C_DECL_VARIABLE_SIZE(TYPE) DECL_LANG_FLAG_0 (TYPE) +/* Store a value in that field. */ +#define C_SET_EXP_ORIGINAL_CODE(EXP, CODE) \ + (TREE_COMPLEXITY (EXP) = (int) (CODE)) + /* Record whether a typedef for type `int' was actually `signed int'. */ #define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP) @@ -85,53 +128,11 @@ struct lang_type GTY(()) /* For a FUNCTION_DECL, nonzero if it was an implicit declaration. */ #define C_DECL_IMPLICIT(EXP) DECL_LANG_FLAG_2 (EXP) -/* For FUNCTION_DECLs, evaluates true if the decl is built-in but has - been declared. */ -#define C_DECL_DECLARED_BUILTIN(EXP) \ - DECL_LANG_FLAG_3 (FUNCTION_DECL_CHECK (EXP)) - -/* For FUNCTION_DECLs, evaluates true if the decl is built-in, has a - built-in prototype and does not have a non-built-in prototype. */ -#define C_DECL_BUILTIN_PROTOTYPE(EXP) \ - DECL_LANG_FLAG_6 (FUNCTION_DECL_CHECK (EXP)) - -/* Record whether a decl was declared register. This is strictly a - front-end flag, whereas DECL_REGISTER is used for code generation; - they may differ for structures with volatile fields. */ -#define C_DECL_REGISTER(EXP) DECL_LANG_FLAG_4 (EXP) - -/* Record whether a decl was used in an expression anywhere except an - unevaluated operand of sizeof / typeof / alignof. This is only - used for functions declared static but not defined, though outside - sizeof and typeof it is set for other function decls as well. */ -#define C_DECL_USED(EXP) DECL_LANG_FLAG_5 (FUNCTION_DECL_CHECK (EXP)) - -/* Record whether a label was defined in a statement expression which - has finished and so can no longer be jumped to. */ -#define C_DECL_UNJUMPABLE_STMT_EXPR(EXP) \ - DECL_LANG_FLAG_6 (LABEL_DECL_CHECK (EXP)) - -/* Record whether a label was the subject of a goto from outside the - current level of statement expression nesting and so cannot be - defined right now. */ -#define C_DECL_UNDEFINABLE_STMT_EXPR(EXP) \ - DECL_LANG_FLAG_7 (LABEL_DECL_CHECK (EXP)) - -/* Record whether a label was defined in the scope of an identifier - with variably modified type which has finished and so can no longer - be jumped to. */ -#define C_DECL_UNJUMPABLE_VM(EXP) \ - DECL_LANG_FLAG_3 (LABEL_DECL_CHECK (EXP)) - -/* Record whether a label was the subject of a goto from outside the - current level of scopes of identifiers with variably modified type - and so cannot be defined right now. */ -#define C_DECL_UNDEFINABLE_VM(EXP) \ - DECL_LANG_FLAG_5 (LABEL_DECL_CHECK (EXP)) - -/* Record whether a variable has been declared threadprivate by - #pragma omp threadprivate. */ -#define C_DECL_THREADPRIVATE_P(DECL) DECL_LANG_FLAG_3 (VAR_DECL_CHECK (DECL)) +/* Nonzero for a declaration of an external object which is not + currently in scope. This is either a built-in declaration of + a library function, before a real declaration has been seen, + or a declaration that appeared in an inner scope that has ended. */ +#define C_DECL_INVISIBLE(EXP) DECL_LANG_FLAG_3 (EXP) /* Nonzero for a decl which either doesn't exist or isn't a prototype. N.B. Could be simplified if all built-in decls had complete prototypes @@ -144,230 +145,12 @@ struct lang_type GTY(()) /* For FUNCTION_TYPE, a hidden list of types of arguments. The same as TYPE_ARG_TYPES for functions with prototypes, but created for functions without prototypes. */ -#define TYPE_ACTUAL_ARG_TYPES(NODE) TYPE_LANG_SLOT_1 (NODE) +#define TYPE_ACTUAL_ARG_TYPES(NODE) TYPE_BINFO (NODE) -/* Record parser information about an expression that is irrelevant - for code generation alongside a tree representing its value. */ -struct c_expr -{ - /* The value of the expression. */ - tree value; - /* Record the original binary operator of an expression, which may - have been changed by fold, STRING_CST for unparenthesized string - constants, or ERROR_MARK for other expressions (including - parenthesized expressions). */ - enum tree_code original_code; -}; - -/* A kind of type specifier. Note that this information is currently - only used to distinguish tag definitions, tag references and typeof - uses. */ -enum c_typespec_kind { - /* A reserved keyword type specifier. */ - ctsk_resword, - /* A reference to a tag, previously declared, such as "struct foo". - This includes where the previous declaration was as a different - kind of tag, in which case this is only valid if shadowing that - tag in an inner scope. */ - ctsk_tagref, - /* A reference to a tag, not previously declared in a visible - scope. */ - ctsk_tagfirstref, - /* A definition of a tag such as "struct foo { int a; }". */ - ctsk_tagdef, - /* A typedef name. */ - ctsk_typedef, - /* An ObjC-specific kind of type specifier. */ - ctsk_objc, - /* A typeof specifier. */ - ctsk_typeof -}; - -/* A type specifier: this structure is created in the parser and - passed to declspecs_add_type only. */ -struct c_typespec { - /* What kind of type specifier this is. */ - enum c_typespec_kind kind; - /* The specifier itself. */ - tree spec; -}; - -/* A storage class specifier. */ -enum c_storage_class { - csc_none, - csc_auto, - csc_extern, - csc_register, - csc_static, - csc_typedef -}; - -/* A type specifier keyword "void", "_Bool", "char", "int", "float", - "double", or none of these. */ -enum c_typespec_keyword { - cts_none, - cts_void, - cts_bool, - cts_char, - cts_int, - cts_float, - cts_double, - cts_dfloat32, - cts_dfloat64, - cts_dfloat128 -}; - -/* A sequence of declaration specifiers in C. */ -struct c_declspecs { - /* The type specified, if a single type specifier such as a struct, - union or enum specifier, typedef name or typeof specifies the - whole type, or NULL_TREE if none or a keyword such as "void" or - "char" is used. Does not include qualifiers. */ - tree type; - /* The attributes from a typedef decl. */ - tree decl_attr; - /* When parsing, the attributes. Outside the parser, this will be - NULL; attributes (possibly from multiple lists) will be passed - separately. */ - tree attrs; - /* Any type specifier keyword used such as "int", not reflecting - modifiers such as "short", or cts_none if none. */ - enum c_typespec_keyword typespec_word; - /* The storage class specifier, or csc_none if none. */ - enum c_storage_class storage_class; - /* Whether any declaration specifiers have been seen at all. */ - BOOL_BITFIELD declspecs_seen_p : 1; - /* Whether a type specifier has been seen. */ - BOOL_BITFIELD type_seen_p : 1; - /* Whether something other than a storage class specifier or - attribute has been seen. This is used to warn for the - obsolescent usage of storage class specifiers other than at the - start of the list. (Doing this properly would require function - specifiers to be handled separately from storage class - specifiers.) */ - BOOL_BITFIELD non_sc_seen_p : 1; - /* Whether the type is specified by a typedef or typeof name. */ - BOOL_BITFIELD typedef_p : 1; - /* Whether a struct, union or enum type either had its content - defined by a type specifier in the list or was the first visible - declaration of its tag. */ - BOOL_BITFIELD tag_defined_p : 1; - /* Whether the type is explicitly "signed" or specified by a typedef - whose type is explicitly "signed". */ - BOOL_BITFIELD explicit_signed_p : 1; - /* Whether the specifiers include a deprecated typedef. */ - BOOL_BITFIELD deprecated_p : 1; - /* Whether the type defaulted to "int" because there were no type - specifiers. */ - BOOL_BITFIELD default_int_p; - /* Whether "long" was specified. */ - BOOL_BITFIELD long_p : 1; - /* Whether "long" was specified more than once. */ - BOOL_BITFIELD long_long_p : 1; - /* Whether "short" was specified. */ - BOOL_BITFIELD short_p : 1; - /* Whether "signed" was specified. */ - BOOL_BITFIELD signed_p : 1; - /* Whether "unsigned" was specified. */ - BOOL_BITFIELD unsigned_p : 1; - /* Whether "complex" was specified. */ - BOOL_BITFIELD complex_p : 1; - /* Whether "inline" was specified. */ - BOOL_BITFIELD inline_p : 1; - /* Whether "__thread" was specified. */ - BOOL_BITFIELD thread_p : 1; - /* Whether "const" was specified. */ - BOOL_BITFIELD const_p : 1; - /* Whether "volatile" was specified. */ - BOOL_BITFIELD volatile_p : 1; - /* Whether "restrict" was specified. */ - BOOL_BITFIELD restrict_p : 1; -}; - -/* The various kinds of declarators in C. */ -enum c_declarator_kind { - /* An identifier. */ - cdk_id, - /* A function. */ - cdk_function, - /* An array. */ - cdk_array, - /* A pointer. */ - cdk_pointer, - /* Parenthesized declarator with nested attributes. */ - cdk_attrs -}; - -/* Information about the parameters in a function declarator. */ -struct c_arg_info { - /* A list of parameter decls. */ - tree parms; - /* A list of structure, union and enum tags defined. */ - tree tags; - /* A list of argument types to go in the FUNCTION_TYPE. */ - tree types; - /* A list of non-parameter decls (notably enumeration constants) - defined with the parameters. */ - tree others; - /* A list of VLA sizes from the parameters. In a function - definition, these are used to ensure that side-effects in sizes - of arrays converted to pointers (such as a parameter int i[n++]) - take place; otherwise, they are ignored. */ - tree pending_sizes; - /* True when these arguments had [*]. */ - BOOL_BITFIELD had_vla_unspec : 1; -}; - -/* A declarator. */ -struct c_declarator { - /* The kind of declarator. */ - enum c_declarator_kind kind; - /* Except for cdk_id, the contained declarator. For cdk_id, NULL. */ - struct c_declarator *declarator; - location_t id_loc; /* Currently only set for cdk_id. */ - union { - /* For identifiers, an IDENTIFIER_NODE or NULL_TREE if an abstract - declarator. */ - tree id; - /* For functions. */ - struct c_arg_info *arg_info; - /* For arrays. */ - struct { - /* The array dimension, or NULL for [] and [*]. */ - tree dimen; - /* The qualifiers inside []. */ - int quals; - /* The attributes (currently ignored) inside []. */ - tree attrs; - /* Whether [static] was used. */ - BOOL_BITFIELD static_p : 1; - /* Whether [*] was used. */ - BOOL_BITFIELD vla_unspec_p : 1; - } array; - /* For pointers, the qualifiers on the pointer type. */ - int pointer_quals; - /* For attributes. */ - tree attrs; - } u; -}; - -/* A type name. */ -struct c_type_name { - /* The declaration specifiers. */ - struct c_declspecs *specs; - /* The declarator. */ - struct c_declarator *declarator; -}; - -/* A parameter. */ -struct c_parm { - /* The declaration specifiers, minus any prefix attributes. */ - struct c_declspecs *specs; - /* The attributes. */ - tree attrs; - /* The declarator. */ - struct c_declarator *declarator; -}; +/* Values for the first parameter to poplevel. */ +#define KEEP_NO 0 +#define KEEP_YES 1 +#define KEEP_MAYBE 2 /* Save and restore the variables in this file and elsewhere that keep track of the progress of compilation of the current function. @@ -376,219 +159,140 @@ struct c_parm { struct language_function GTY(()) { struct c_language_function base; - tree x_break_label; - tree x_cont_label; - struct c_switch * GTY((skip)) x_switch_stack; - struct c_arg_info * GTY((skip)) arg_info; int returns_value; int returns_null; int returns_abnormally; int warn_about_return_type; int extern_inline; -}; - -/* Save lists of labels used or defined in particular contexts. - Allocated on the parser obstack. */ - -struct c_label_list -{ - /* The label at the head of the list. */ - tree label; - /* The rest of the list. */ - struct c_label_list *next; -}; - -/* Statement expression context. */ - -struct c_label_context_se -{ - /* The labels defined at this level of nesting. */ - struct c_label_list *labels_def; - /* The labels used at this level of nesting. */ - struct c_label_list *labels_used; - /* The next outermost context. */ - struct c_label_context_se *next; -}; - -/* Context of variably modified declarations. */ - -struct c_label_context_vm -{ - /* The labels defined at this level of nesting. */ - struct c_label_list *labels_def; - /* The labels used at this level of nesting. */ - struct c_label_list *labels_used; - /* The scope of this context. Multiple contexts may be at the same - numbered scope, since each variably modified declaration starts a - new context. */ - unsigned scope; - /* The next outermost context. */ - struct c_label_context_vm *next; + int x_in_iteration_stmt; + int x_in_case_stmt; }; -/* in c-parser.c */ +/* in c-parse.in */ extern void c_parse_init (void); /* in c-aux-info.c */ extern void gen_aux_info_record (tree, int, int, int); /* in c-decl.c */ -extern struct obstack parser_obstack; -extern tree c_break_label; -extern tree c_cont_label; +extern int c_in_iteration_stmt; +extern int c_in_case_stmt; extern int global_bindings_p (void); -extern void push_scope (void); -extern tree pop_scope (void); +extern tree getdecls (void); +extern void pushlevel (int); extern void insert_block (tree); +extern void set_block (tree); +extern tree pushdecl (tree); extern void c_expand_body (tree); extern void c_init_decl_processing (void); extern void c_dup_lang_specific_decl (tree); extern void c_print_identifier (FILE *, tree, int); -extern int quals_from_declspecs (const struct c_declspecs *); -extern struct c_declarator *build_array_declarator (tree, struct c_declspecs *, - bool, bool); +extern tree build_array_declarator (tree, tree, int, int); extern tree build_enumerator (tree, tree); -extern tree check_for_loop_decls (void); +extern void check_for_loop_decls (void); extern void mark_forward_parm_decls (void); +extern int complete_array_type (tree, tree, int); extern void declare_parm_level (void); -extern void undeclared_variable (tree, location_t); +extern void undeclared_variable (tree); extern tree declare_label (tree); extern tree define_label (location_t, tree); -extern void c_maybe_initialize_eh (void); extern void finish_decl (tree, tree, tree); extern tree finish_enum (tree, tree, tree); extern void finish_function (void); extern tree finish_struct (tree, tree, tree); -extern struct c_arg_info *get_parm_info (bool); -extern tree grokfield (struct c_declarator *, struct c_declspecs *, tree); -extern tree groktypename (struct c_type_name *); -extern tree grokparm (const struct c_parm *); +extern tree get_parm_info (int); +extern tree grokfield (tree, tree, tree); +extern tree groktypename (tree); +extern tree groktypename_in_parm_context (tree); extern tree implicitly_declare (tree); +extern int in_parm_level_p (void); extern void keep_next_level (void); +extern tree lookup_name (tree); extern void pending_xref_error (void); extern void c_push_function_context (struct function *); extern void c_pop_function_context (struct function *); -extern void push_parm_decl (const struct c_parm *); -extern struct c_declarator *set_array_declarator_inner (struct c_declarator *, - struct c_declarator *, - bool); -extern tree builtin_function (const char *, tree, int, enum built_in_class, - const char *, tree); -extern void shadow_tag (const struct c_declspecs *); -extern void shadow_tag_warned (const struct c_declspecs *, int); +extern void push_parm_decl (tree); +extern tree pushdecl_top_level (tree); +extern void pushtag (tree, tree); +extern tree set_array_declarator_type (tree, tree, int); +extern void shadow_tag (tree); +extern void shadow_tag_warned (tree, int); extern tree start_enum (tree); -extern int start_function (struct c_declspecs *, struct c_declarator *, tree); -extern tree start_decl (struct c_declarator *, struct c_declspecs *, bool, - tree); +extern int start_function (tree, tree, tree); +extern tree start_decl (tree, tree, int, tree); extern tree start_struct (enum tree_code, tree); extern void store_parm_decls (void); -extern void store_parm_decls_from (struct c_arg_info *); extern tree xref_tag (enum tree_code, tree); -extern struct c_typespec parser_xref_tag (enum tree_code, tree); -extern int c_expand_decl (tree); -extern struct c_parm *build_c_parm (struct c_declspecs *, tree, - struct c_declarator *); -extern struct c_declarator *build_attrs_declarator (tree, - struct c_declarator *); -extern struct c_declarator *build_function_declarator (struct c_arg_info *, - struct c_declarator *); -extern struct c_declarator *build_id_declarator (tree); -extern struct c_declarator *make_pointer_declarator (struct c_declspecs *, - struct c_declarator *); -extern struct c_declspecs *build_null_declspecs (void); -extern struct c_declspecs *declspecs_add_qual (struct c_declspecs *, tree); -extern struct c_declspecs *declspecs_add_type (struct c_declspecs *, - struct c_typespec); -extern struct c_declspecs *declspecs_add_scspec (struct c_declspecs *, tree); -extern struct c_declspecs *declspecs_add_attrs (struct c_declspecs *, tree); -extern struct c_declspecs *finish_declspecs (struct c_declspecs *); +extern tree c_begin_compound_stmt (void); +extern void c_expand_deferred_function (tree); +extern void c_expand_decl_stmt (tree); +extern void c_static_assembler_name (tree); +extern tree make_pointer_declarator (tree, tree); +extern void merge_translation_unit_decls (void); /* in c-objc-common.c */ extern int c_disregard_inline_limits (tree); extern int c_cannot_inline_tree_fn (tree *); extern bool c_objc_common_init (void); -extern bool c_missing_noreturn_ok_p (tree); -extern tree c_objc_common_truthvalue_conversion (tree expr); +extern int c_missing_noreturn_ok_p (tree); +extern void c_objc_common_finish_file (void); +extern int defer_fn (tree); extern bool c_warn_unused_global_decl (tree); -extern void c_initialize_diagnostics (diagnostic_context *); -extern bool c_vla_unspec_p (tree x, tree fn); #define c_build_type_variant(TYPE, CONST_P, VOLATILE_P) \ c_build_qualified_type ((TYPE), \ ((CONST_P) ? TYPE_QUAL_CONST : 0) | \ ((VOLATILE_P) ? TYPE_QUAL_VOLATILE : 0)) +#define c_sizeof_nowarn(T) c_sizeof_or_alignof_type (T, SIZEOF_EXPR, 0) + /* in c-typeck.c */ -extern int in_alignof; -extern int in_sizeof; -extern int in_typeof; -extern struct c_switch *c_switch_stack; -extern struct c_label_context_se *label_context_stack_se; -extern struct c_label_context_vm *label_context_stack_vm; +/* For use with comptypes. */ +enum { + COMPARE_STRICT = 0 +}; extern tree require_complete_type (tree); -extern int same_translation_unit_p (tree, tree); -extern int comptypes (tree, tree); -extern bool c_vla_type_p (tree); +extern int comptypes (tree, tree, int); +extern tree c_size_in_bytes (tree); extern bool c_mark_addressable (tree); extern void c_incomplete_type_error (tree, tree); extern tree c_type_promotes_to (tree); -extern struct c_expr default_function_array_conversion (struct c_expr); -extern tree composite_type (tree, tree); extern tree build_component_ref (tree, tree); +extern tree build_indirect_ref (tree, const char *); extern tree build_array_ref (tree, tree); -extern tree build_external_ref (tree, int, location_t); -extern void pop_maybe_used (bool); -extern struct c_expr c_expr_sizeof_expr (struct c_expr); -extern struct c_expr c_expr_sizeof_type (struct c_type_name *); -extern struct c_expr parser_build_unary_op (enum tree_code, struct c_expr); -extern struct c_expr parser_build_binary_op (enum tree_code, struct c_expr, - struct c_expr); +extern tree build_external_ref (tree, int); +extern tree parser_build_binary_op (enum tree_code, tree, tree); +extern int c_tree_expr_nonnegative_p (tree); +extern void readonly_error (tree, const char *); extern tree build_conditional_expr (tree, tree, tree); -extern tree build_compound_expr (tree, tree); -extern tree c_cast_expr (struct c_type_name *, tree); +extern tree build_compound_expr (tree); +extern tree c_cast_expr (tree, tree); extern tree build_c_cast (tree, tree); +extern tree build_modify_expr (tree, enum tree_code, tree); extern void store_init_value (tree, tree); extern void error_init (const char *); extern void pedwarn_init (const char *); -extern void maybe_warn_string_init (tree, struct c_expr); extern void start_init (tree, tree, int); extern void finish_init (void); extern void really_start_incremental_init (tree); extern void push_init_level (int); -extern struct c_expr pop_init_level (int); +extern tree pop_init_level (int); extern void set_init_index (tree, tree); extern void set_init_label (tree); -extern void process_init_element (struct c_expr); +extern void process_init_element (tree); extern tree build_compound_literal (tree, tree); +extern void pedwarn_c90 (const char *, ...) ATTRIBUTE_PRINTF_1; +extern void pedwarn_c99 (const char *, ...) ATTRIBUTE_PRINTF_1; extern tree c_start_case (tree); -extern void c_finish_case (tree); -extern tree build_asm_expr (tree, tree, tree, tree, bool); -extern tree build_asm_stmt (tree, tree); +extern void c_finish_case (void); +extern tree simple_asm_stmt (tree); +extern tree build_asm_stmt (tree, tree, tree, tree, tree); extern tree c_convert_parm_for_inlining (tree, tree, tree, int); -extern int c_types_compatible_p (tree, tree); -extern tree c_begin_compound_stmt (bool); -extern tree c_end_compound_stmt (tree, bool); -extern void c_finish_if_stmt (location_t, tree, tree, tree, bool); -extern void c_finish_loop (location_t, tree, tree, tree, tree, tree, bool); -extern tree c_begin_stmt_expr (void); -extern tree c_finish_stmt_expr (tree); -extern tree c_process_expr_stmt (tree); -extern tree c_finish_expr_stmt (tree); -extern tree c_finish_return (tree); -extern tree c_finish_bc_stmt (tree *, bool); -extern tree c_finish_goto_label (tree); -extern tree c_finish_goto_ptr (tree); -extern void c_begin_vm_scope (unsigned int); -extern void c_end_vm_scope (unsigned int); -extern tree c_expr_to_decl (tree, bool *, bool *, bool *); -extern tree c_begin_omp_parallel (void); -extern tree c_finish_omp_parallel (tree, tree); -extern tree c_finish_omp_clauses (tree); /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ @@ -609,28 +313,18 @@ extern int current_function_returns_abnormally; extern int system_header_p; -/* True means global_bindings_p should return false even if the scope stack - says we are in file scope. */ - -extern bool c_override_global_bindings_to_false; - -/* True means we've initialized exception handling. */ -extern bool c_eh_initialized_p; - /* In c-decl.c */ extern void c_finish_incomplete_decl (tree); +extern void *get_current_scope (void); +extern void objc_mark_locals_volatile (void *); extern void c_write_global_declarations (void); +extern GTY(()) tree static_ctors; +extern GTY(()) tree static_dtors; + /* In order for the format checking to accept the C frontend diagnostic framework extensions, you must include this file before toplev.h, not after. */ -#if GCC_VERSION >= 4001 -#define ATTRIBUTE_GCC_CDIAG(m, n) __attribute__ ((__format__ (GCC_DIAG_STYLE, m ,n))) ATTRIBUTE_NONNULL(m) -#else -#define ATTRIBUTE_GCC_CDIAG(m, n) ATTRIBUTE_NONNULL(m) -#endif - -extern void pedwarn_c90 (const char *, ...) ATTRIBUTE_GCC_CDIAG(1,2); -extern void pedwarn_c99 (const char *, ...) ATTRIBUTE_GCC_CDIAG(1,2); +#define GCC_DIAG_STYLE __gcc_cdiag__ #endif /* ! GCC_C_TREE_H */ diff --git a/contrib/gcc/c.opt b/contrib/gcc/c.opt index 01f47fc..0568463 100644 --- a/contrib/gcc/c.opt +++ b/contrib/gcc/c.opt @@ -1,5 +1,5 @@ ; Options for the C, ObjC, C++ and ObjC++ front ends. -; Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +; Copyright (C) 2003 Free Software Foundation, Inc. ; ; This file is part of GCC. ; @@ -7,21 +7,60 @@ ; 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. -; +; ; GCC 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 GCC; see the file COPYING. If not, write to the Free -; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -; 02110-1301, USA. - -; See the GCC internals manual for a description of this file's format. +; Software Foundation, 59 Temple Place - Suite 330, Boston, MA +; 02111-1307, USA. + + +; This file is processed by the script opts.sh. It is a database of +; command line options, with each record separated by a blank line, +; and each field appearing on its own line. The first field is the +; command-line switch with the leading "-" removed. All options +; beginning with "f" or "W" are implicitly assumed to take a "no-" +; form; this form should not be listed. If you do not want this +; negative form and you want it to be automatically rejected, add +; RejectNegative to the second field. + +; The second field is a space-separated list of which parts of the +; compiler recognize the switch, as declared by "Language" entries. +; If the switch takes an argument, then you should also specify +; "Joined" and/or "Separate" to indicate where the argument can +; appear. If a Joined argument can legitimately be omitted, specify +; "JoinedOrMissing" instead of "Joined". If the argument to a switch +; is a non-negative integer, you can specify "UInteger" and the switch +; decoder will convert the argument for you, or complain to the user +; if the argument is invalid. + +; The third field is the help text to output with --help. This is +; automatically line-wrapped on output. Normally the switch is output +; automatically, with the help text on the right hand side of the +; output. However, if the help text contains a tab character, the +; text to the left of the tab is output instead of the switch, and the +; text to its right forms the help. This is useful for elaborating on +; what type of argument a switch takes, for example. If the second +; field contains "Undocumented" then nothing is output with --help. +; Only do this with good reason like the switch being internal between +; the driver and the front end - it is not an excuse to leave a switch +; undocumented. + +; Comments can appear on their own line anwhere in the file, preceded +; by a semicolon. Whitespace is permitted before the semicolon. + +; For each switch XXX below, an enumeration constant is created by the +; script opts.sh spelt OPT_XXX, but with all non-alphanumeric +; characters replaced with an underscore. ; Please try to keep this file in ASCII collating order. +; $FreeBSD$ + Language C @@ -56,17 +95,13 @@ C ObjC C++ ObjC++ Joined Separate E C ObjC C++ ObjC++ Undocumented -F -C ObjC C++ ObjC++ Joined Separate --F <dir> Add <dir> to the end of the main framework include path - H C ObjC C++ ObjC++ Print the name of header files as they are used I C ObjC C++ ObjC++ Joined Separate --I <dir> Add <dir> to the end of the main include path +-I <dir> Add <dir> to the end of the main include path. -I- gives more include path control; see info documentation M C ObjC C++ ObjC++ @@ -113,36 +148,22 @@ C ObjC C++ ObjC++ Joined Separate -U<macro> Undefine <macro> Wabi -C++ ObjC++ Var(warn_abi) -Warn about things that will change when compiling with an ABI-compliant compiler - -Waddress -C ObjC C++ ObjC++ Var(warn_address) -Warn about suspicious uses of memory addresses +C++ ObjC++ Wall C ObjC C++ ObjC++ Enable most warning messages -Wassign-intercept -ObjC ObjC++ Var(warn_assign_intercept) -Warn whenever an Objective-C assignment is being intercepted by the garbage collector - Wbad-function-cast -C ObjC Var(warn_bad_function_cast) +C ObjC Warn about casting functions to incompatible types -Wc++-compat -C ObjC Var(warn_cxx_compat) -Warn about C constructs that are not in the common subset of C and C++ - - Wcast-qual -C ObjC C++ ObjC++ Var(warn_cast_qual) +C ObjC C++ ObjC++ Warn about casts which discard qualifiers Wchar-subscripts -C ObjC C++ ObjC++ Var(warn_char_subscripts) +C ObjC C++ ObjC++ Warn about subscripts whose type is \"char\" Wcomment @@ -154,27 +175,27 @@ C ObjC C++ ObjC++ Synonym for -Wcomment Wconversion -C ObjC C++ ObjC++ Var(warn_conversion) +C ObjC C++ ObjC++ Warn about possibly confusing type conversions Wctor-dtor-privacy -C++ ObjC++ Var(warn_ctor_dtor_privacy) +C++ ObjC++ Warn when all constructors and destructors are private Wdeclaration-after-statement -C ObjC Var(warn_declaration_after_statement) +C ObjC Warn when a declaration is found after a statement Wdeprecated -C++ ObjC++ Var(warn_deprecated) Init(1) +C++ ObjC++ Warn about deprecated compiler features Wdiv-by-zero -C ObjC C++ ObjC++ Var(warn_div_by_zero) Init(1) +C ObjC Warn about compile-time integer division by zero Weffc++ -C++ ObjC++ Var(warn_ecpp) +C++ ObjC++ Warn about violations of Effective C++ style rules Wendif-labels @@ -190,7 +211,7 @@ C ObjC RejectNegative Make implicit function declarations an error Wfloat-equal -C ObjC C++ ObjC++ Var(warn_float_equal) +C ObjC C++ ObjC++ Warn if testing floating point numbers for equality Wformat @@ -198,53 +219,48 @@ C ObjC C++ ObjC++ Warn about printf/scanf/strftime/strfmon format string anomalies Wformat-extra-args -C ObjC C++ ObjC++ Var(warn_format_extra_args) +C ObjC C++ ObjC++ Warn if passing too many arguments to a function for its format string Wformat-nonliteral -C ObjC C++ ObjC++ Var(warn_format_nonliteral) +C ObjC C++ ObjC++ Warn about format strings that are not literals Wformat-security -C ObjC C++ ObjC++ Var(warn_format_security) +C ObjC C++ ObjC++ Warn about possible security problems with format functions Wformat-y2k -C ObjC C++ ObjC++ Var(warn_format_y2k) +C ObjC C++ ObjC++ Warn about strftime formats yielding 2-digit years Wformat-zero-length -C ObjC Var(warn_format_zero_length) -Warn about zero-length formats +C ObjC Wformat= C ObjC C++ ObjC++ Joined Winit-self -C ObjC C++ ObjC++ Var(warn_init_self) -Warn about variables which are initialized to themselves +C ObjC C++ ObjC++ +Warn about variables which are initialized to themselves. Wimplicit C ObjC C++ ObjC++ Wimplicit-function-declaration -C ObjC Var(mesg_implicit_function_declaration) Init(-1) +C ObjC Warn about implicit function declarations Wimplicit-int -C ObjC Var(warn_implicit_int) +C ObjC Warn when a declaration does not specify a type Wimport C ObjC C++ ObjC++ -Deprecated. This switch has no effect - -Wint-to-pointer-cast -C ObjC Var(warn_int_to_pointer_cast) Init(1) -Warn when there is a cast to a pointer from an integer of a different size +Deprecated. This switch has no effect. Winvalid-offsetof -C++ ObjC++ Var(warn_invalid_offsetof) Init(1) +C++ ObjC++ Warn about invalid uses of the \"offsetof\" macro Winvalid-pch @@ -252,7 +268,7 @@ C ObjC C++ ObjC++ Warn about PCH files that are found but not used Wlong-long -C ObjC C++ ObjC++ Var(warn_long_long) Init(1) +C ObjC C++ ObjC++ Do not warn about using \"long long\" when -pedantic Wmain @@ -260,27 +276,19 @@ C ObjC Warn about suspicious declarations of \"main\" Wmissing-braces -C ObjC C++ ObjC++ Var(warn_missing_braces) +C ObjC C++ ObjC++ Warn about possibly missing braces around initializers Wmissing-declarations -C ObjC Var(warn_missing_declarations) +C ObjC Warn about global functions without previous declarations -Wmissing-field-initializers -C ObjC C++ ObjC++ Var(warn_missing_field_initializers) Init(-1) -Warn about missing fields in struct initializers - Wmissing-format-attribute -C ObjC C++ ObjC++ Var(warn_missing_format_attribute) -Warn about functions which might be candidates for format attributes - -Wmissing-include-dirs C ObjC C++ ObjC++ -Warn about user-specified include directories that do not exist +Warn about functions which might be candidates for format attributes Wmissing-prototypes -C ObjC Var(warn_missing_prototypes) +C ObjC Warn about global functions without prototypes Wmultichar @@ -288,111 +296,82 @@ C ObjC C++ ObjC++ Warn about use of multi-character character constants Wnested-externs -C ObjC Var(warn_nested_externs) +C ObjC Warn about \"extern\" declarations not at file scope Wnon-template-friend -C++ ObjC++ Var(warn_nontemplate_friend) Init(1) +C++ ObjC++ Warn when non-templatized friend functions are declared within a template Wnon-virtual-dtor -C++ ObjC++ Var(warn_nonvdtor) +C++ ObjC++ Warn about non-virtual destructors Wnonnull -C ObjC Var(warn_nonnull) -Warn about NULL being passed to argument slots marked as requiring non-NULL - -Wnormalized= -C ObjC C++ ObjC++ Joined --Wnormalized=<id|nfc|nfkc> Warn about non-normalised Unicode strings +C ObjC Wold-style-cast -C++ ObjC++ Var(warn_old_style_cast) +C++ ObjC++ Warn if a C-style cast is used in a program Wold-style-definition -C ObjC Var(warn_old_style_definition) +C ObjC Warn if an old-style parameter definition is used -Woverlength-strings -C ObjC C++ ObjC++ Var(warn_overlength_strings) Init(-1) -Warn if a string is longer than the maximum portable length specified by the standard - Woverloaded-virtual -C++ ObjC++ Var(warn_overloaded_virtual) +C++ ObjC++ Warn about overloaded virtual function names -Woverride-init -C ObjC Var(warn_override_init) Init(-1) -Warn about overriding initializers without side effects - Wparentheses -C ObjC C++ ObjC++ Var(warn_parentheses) +C ObjC C++ ObjC++ Warn about possibly missing parentheses Wpmf-conversions -C++ ObjC++ Var(warn_pmf2ptr) Init(1) +C++ ObjC++ Warn when converting the type of pointers to member functions Wpointer-arith -C ObjC C++ ObjC++ Var(warn_pointer_arith) +C ObjC C++ ObjC++ Warn about function pointer arithmetic -Wpointer-to-int-cast -C ObjC Var(warn_pointer_to_int_cast) Init(1) -Warn when a pointer is cast to an integer of a different size - -Wpragmas -C ObjC C++ ObjC++ Var(warn_pragmas) Init(1) -Warn about misuses of pragmas - Wprotocol -ObjC ObjC++ Var(warn_protocol) Init(1) +ObjC ObjC++ Warn if inherited methods are unimplemented Wredundant-decls -C ObjC C++ ObjC++ Var(warn_redundant_decls) +C ObjC C++ ObjC++ Warn about multiple declarations of the same object Wreorder -C++ ObjC++ Var(warn_reorder) +C++ ObjC++ Warn when the compiler reorders code Wreturn-type -C ObjC C++ ObjC++ Var(warn_return_type) +C ObjC C++ ObjC++ Warn whenever a function's return type defaults to \"int\" (C), or about inconsistent return types (C++) Wselector -ObjC ObjC++ Var(warn_selector) +ObjC ObjC++ Warn if a selector has multiple methods Wsequence-point -C ObjC C++ ObjC++ Var(warn_sequence_point) +C ObjC Warn about possible violations of sequence point rules Wsign-compare -C ObjC C++ ObjC++ Var(warn_sign_compare) Init(-1) +C ObjC C++ ObjC++ Warn about signed-unsigned comparisons Wsign-promo -C++ ObjC++ Var(warn_sign_promo) -Warn when overload promotes from unsigned to signed - -Wstrict-null-sentinel C++ ObjC++ -Warn about uncasted NULL used as sentinel +Warn when overload promotes from unsigned to signed Wstrict-prototypes -C ObjC Var(warn_strict_prototypes) +C ObjC Warn about unprototyped function declarations -Wstrict-selector-match -ObjC ObjC++ Var(warn_strict_selector_match) -Warn if type signatures of candidate methods do not match exactly - Wsynth -C++ ObjC++ Var(warn_synth) +C++ ObjC++ Warn when synthesis behavior differs from Cfront Wsystem-headers @@ -400,7 +379,7 @@ C ObjC C++ ObjC++ Do not suppress warnings from system headers Wtraditional -C ObjC Var(warn_traditional) +C ObjC Warn about features not present in traditional C Wtrigraphs @@ -408,8 +387,7 @@ C ObjC C++ ObjC++ Warn if trigraphs are encountered that might affect the meaning of the program Wundeclared-selector -ObjC ObjC++ Var(warn_undeclared_selector) -Warn about @selector()s without previously declared methods +ObjC ObjC++ Wundef C ObjC C++ ObjC++ @@ -423,21 +401,13 @@ Wunused-macros C ObjC C++ ObjC++ Warn about macros defined in the main file that are not used -Wvariadic-macros -C ObjC C++ ObjC++ -Do not warn about using variadic macros when -pedantic - Wwrite-strings -C ObjC C++ ObjC++ Var(warn_write_strings) -In C++, nonzero means warn about deprecated conversion from string literals to `char *'. In C, similar warning, except that the conversion is of course not deprecated by the ISO C standard. - -Wpointer-sign -C ObjC Var(warn_pointer_sign) Init(-1) -Warn when a pointer differs in signedness in an assignment +C ObjC C++ ObjC++ +Give strings the type \"array of char\" ansi C ObjC C++ ObjC++ -A synonym for -std=c89 (for C) or -std=c++98 (for C++) +A synonym for -std=c89 (for C) or -std=c++98 (for C++). d C ObjC C++ ObjC++ Joined @@ -477,6 +447,10 @@ fconserve-space C++ ObjC++ Reduce the size of object files +fconst-strings +C++ ObjC++ +Make string literals \"const char[]\" not \"char[]\" + fconstant-string-class= ObjC ObjC++ Joined -fconst-string-class=<name> Use class <name> for constant strings @@ -489,6 +463,10 @@ fdollars-in-identifiers C ObjC C++ ObjC++ Permit '$' as an identifier character +fdump- +C ObjC C++ ObjC++ Joined RejectNegative +-fdump-<type> Dump various compiler internals to a file + felide-constructors C++ ObjC++ @@ -503,18 +481,20 @@ fexec-charset= C ObjC C++ ObjC++ Joined RejectNegative -fexec-charset=<cset> Convert all strings and character constants to character set <cset> -fextended-identifiers -C ObjC C++ ObjC++ -Permit universal character names (\\u and \\U) in identifiers - finput-charset= C ObjC C++ ObjC++ Joined RejectNegative --finput-charset=<cset> Specify the default character set for source files +-finput-charset=<cset> Specify the default character set for source files. fexternal-templates C++ ObjC++ +ffixed-form +C ObjC + +ffixed-line-length- +C ObjC Joined + ffor-scope C++ ObjC++ Scope of for-init-statement variables is local to the loop @@ -531,10 +511,6 @@ fgnu-runtime ObjC ObjC++ Generate code for GNU runtime environment -fgnu89-inline -C ObjC Var(flag_gnu89_inline) Init(-1) -Use traditional GNU semantics for inline functions - fguiding-decls C++ ObjC++ @@ -564,10 +540,6 @@ fimplicit-templates C++ ObjC++ Emit implicit instantiations of templates -ffriend-injection -C++ ObjC++ Var(flag_friend_injection) -Inject friend functions into enclosing namespace - flabels-ok C++ ObjC++ @@ -595,35 +567,10 @@ C++ ObjC++ fnonnull-objects C++ ObjC++ -; Generate special '- .cxx_construct' and '- .cxx_destruct' methods -; to initialize any non-POD ivars in Objective-C++ classes. -fobjc-call-cxx-cdtors -ObjC++ Var(flag_objc_call_cxx_cdtors) -Generate special Objective-C methods to initialize/destroy non-POD C++ ivars, if needed - -fobjc-direct-dispatch -ObjC ObjC++ Var(flag_objc_direct_dispatch) -Allow fast jumps to the message dispatcher - -; Nonzero means that we will allow new ObjC exception syntax (@throw, -; @try, etc.) in source code. fobjc-exceptions -ObjC ObjC++ Var(flag_objc_exceptions) +ObjC ObjC++ Enable Objective-C exception and synchronization syntax -fobjc-gc -ObjC ObjC++ Var(flag_objc_gc) -Enable garbage collection (GC) in Objective-C/Objective-C++ programs - -; Nonzero means that we generate NeXT setjmp based exceptions. -fobjc-sjlj-exceptions -ObjC ObjC++ Var(flag_objc_sjlj_exceptions) Init(-1) -Enable Objective-C setjmp exception handling runtime - -fopenmp -C ObjC C++ ObjC++ Var(flag_openmp) -Enable OpenMP - foperator-names C++ ObjC++ Recognize C++ kewords like \"compl\" and \"xor\" @@ -635,10 +582,6 @@ Enable optional diagnostics fpch-deps C ObjC C++ ObjC++ -fpch-preprocess -C ObjC C++ ObjC++ -Look for and use PCH files even when preprocessing - fpermissive C++ ObjC++ Downgrade conformance errors to warnings @@ -671,6 +614,9 @@ fshort-wchar C ObjC C++ ObjC++ Force the underlying type for \"wchar_t\" to be \"unsigned short\" +fshow-column +C ObjC C++ ObjC++ + fsigned-bitfields C ObjC C++ ObjC++ When \"signed\" or \"unsigned\" is not given make the bitfield signed @@ -694,16 +640,12 @@ C ObjC C++ ObjC++ Joined RejectNegative UInteger -ftabstop=<number> Distance between tab stops for column reporting ftemplate-depth- -C++ ObjC++ Joined RejectNegative UInteger +C++ ObjC++ Joined RejectNegative UInteger -ftemplate-depth-<number> Specify maximum template instantiation depth fthis-is-variable C++ ObjC++ -fthreadsafe-statics -C++ ObjC++ --fno-threadsafe-statics Do not generate thread-safe code for initializing local statics - funsigned-bitfields C ObjC C++ ObjC++ When \"signed\" or \"unsigned\" is not given make the bitfield unsigned @@ -716,14 +658,6 @@ fuse-cxa-atexit C++ ObjC++ Use __cxa_atexit to register destructors -fuse-cxa-get-exception-ptr -C++ ObjC++ -Use __cxa_get_exception_ptr in exception handling - -fvisibility-inlines-hidden -C++ ObjC++ -Marks all inlined methods as having hidden visibility - fvtable-gc C++ ObjC++ Discard unused virtual functions @@ -764,10 +698,6 @@ imacros C ObjC C++ ObjC++ Joined Separate -imacros <file> Accept definition of macros in <file> -imultilib -C ObjC C++ ObjC++ Joined Separate --imultilib <dir> Set <dir> to be the multilib include subdirectory - include C ObjC C++ ObjC++ Joined Separate -include <file> Include the contents of <file> before other files @@ -784,10 +714,6 @@ isystem C ObjC C++ ObjC++ Joined Separate -isystem <dir> Add <dir> to the start of the system include path -iquote -C ObjC C++ ObjC++ Joined Separate --iquote <dir> Add <dir> to the end of the quote include path - iwithprefix C ObjC C++ ObjC++ Joined Separate -iwithprefix <dir> Add <dir> to the end of the system include path @@ -799,9 +725,6 @@ C ObjC C++ ObjC++ Joined Separate lang-asm C Undocumented -lang-fortran -C Undocumented - lang-objc C ObjC C++ ObjC++ Undocumented @@ -829,10 +752,6 @@ print-objc-runtime-info ObjC ObjC++ Generate C header of platform-specific features -print-pch-checksum -C ObjC C++ ObjC++ -Print a checksum of the executable for PCH validity checking, and stop - remap C ObjC C++ ObjC++ Remap file names when including files @@ -905,4 +824,8 @@ w C ObjC C++ ObjC++ ; Documented in common.opt +fformat-extensions +C ObjC C++ ObjC++ +Enable FreeBSD format extensions + ; This comment is to ensure we retain the blank line above. diff --git a/contrib/gcc/choose-temp.c b/contrib/gcc/choose-temp.c index 5c2c614..7f33f83 100644 --- a/contrib/gcc/choose-temp.c +++ b/contrib/gcc/choose-temp.c @@ -17,6 +17,8 @@ License along with libiberty; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $FreeBSD$ */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/contrib/gcc/config/alpha/elf.h b/contrib/gcc/config/alpha/elf.h index 34bba3e..97b15fe 100644 --- a/contrib/gcc/config/alpha/elf.h +++ b/contrib/gcc/config/alpha/elf.h @@ -20,9 +20,11 @@ along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $FreeBSD$ */ + #undef OBJECT_FORMAT_COFF #undef EXTENDED_COFF -#define OBJECT_FORMAT_ELF +#define OBJECT_FORMAT_ELF 1 /* ??? Move all SDB stuff from alpha.h to osf.h. */ #undef SDB_DEBUGGING_INFO diff --git a/contrib/gcc/config/alpha/freebsd.h b/contrib/gcc/config/alpha/freebsd.h index 0b29361..b007989 100644 --- a/contrib/gcc/config/alpha/freebsd.h +++ b/contrib/gcc/config/alpha/freebsd.h @@ -19,6 +19,7 @@ along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $FreeBSD$ */ #undef SUBTARGET_EXTRA_SPECS #define SUBTARGET_EXTRA_SPECS \ @@ -33,6 +34,7 @@ Boston, MA 02111-1307, USA. */ #define FBSD_TARGET_CPU_CPP_BUILTINS() \ do \ { \ + builtin_define ("__LP64__"); \ if (flag_pic) \ { \ builtin_define ("__PIC__"); \ @@ -56,6 +58,12 @@ Boston, MA 02111-1307, USA. */ %{static:-Bstatic}} \ %{symbolic:-Bsymbolic}" +/* Reset our STARTFILE_SPEC because of a moronic pigheaded + Linuxism(glibc'ism) that was added to alpha/elf.h. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC FBSD_STARTFILE_SPEC + /************************[ Target stuff ]***********************************/ @@ -69,10 +77,28 @@ Boston, MA 02111-1307, USA. */ #undef WCHAR_TYPE_SIZE #define WCHAR_TYPE_SIZE 32 +/* Handle cross-compilation on 32-bits machines (such as i386) for 64-bits + machines (Alpha in this case). */ + +#if defined(__i386__) +#undef HOST_BITS_PER_LONG +#define HOST_BITS_PER_LONG 32 +#undef HOST_WIDE_INT +#define HOST_WIDE_INT long long +#undef HOST_BITS_PER_WIDE_INT +#define HOST_BITS_PER_WIDE_INT 64 +#endif + +/* This is the pseudo-op used to generate a 64-bit word of data with a + specific value in some section. */ + #undef TARGET_VERSION -#define TARGET_VERSION fprintf (stderr, " (FreeBSD/alpha ELF)"); +#define TARGET_VERSION fprintf (stderr, " (FreeBSD/Alpha ELF)"); + +#define TARGET_ELF 1 -#define TARGET_ELF 1 +#undef OBJECT_FORMAT_COFF +#undef EXTENDED_COFF #undef TARGET_DEFAULT #define TARGET_DEFAULT (MASK_FP | MASK_FPREGS | MASK_GAS) @@ -83,6 +109,17 @@ Boston, MA 02111-1307, USA. */ #undef TARGET_PROFILING_NEEDS_GP #define TARGET_PROFILING_NEEDS_GP 1 +/* We always use gas here, so we don't worry about ECOFF assembler problems. */ +#undef TARGET_GAS +#define TARGET_GAS 1 + + +/************************[ Assembler stuff ]********************************/ + + + +/************************[ Debugger stuff ]*********************************/ + /* This is the char to use for continuation (in case we need to turn continuation back on). */ diff --git a/contrib/gcc/config/freebsd-spec.h b/contrib/gcc/config/freebsd-spec.h index b3f18e2..a070936 100644 --- a/contrib/gcc/config/freebsd-spec.h +++ b/contrib/gcc/config/freebsd-spec.h @@ -1,5 +1,5 @@ /* Base configuration file for all FreeBSD targets. - Copyright (C) 1999, 2000, 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GCC. @@ -15,8 +15,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* $FreeBSD$ */ /* Common FreeBSD configuration. All FreeBSD architectures should include this file, which will specify @@ -57,41 +59,63 @@ Boston, MA 02110-1301, USA. */ builtin_assert ("system=unix"); \ builtin_assert ("system=bsd"); \ builtin_assert ("system=FreeBSD"); \ + FBSD_NATIVE_TARGET_OS_CPP_BUILTINS(); \ FBSD_TARGET_CPU_CPP_BUILTINS(); \ } \ while (0) -/* Define the default FreeBSD-specific per-CPU hook code. */ +/* Define the default FreeBSD-specific per-CPU hook code. */ #define FBSD_TARGET_CPU_CPP_BUILTINS() do {} while (0) +#ifdef FREEBSD_NATIVE +#define FBSD_NATIVE_TARGET_OS_CPP_BUILTINS() \ + do { \ + builtin_define_with_int_value ("__FreeBSD_cc_version", FBSD_CC_VER); \ + } while (0) +#else +#define FBSD_NATIVE_TARGET_OS_CPP_BUILTINS() \ + do {} while (0) +#endif + /* Provide a CPP_SPEC appropriate for FreeBSD. We just deal with the GCC - option `-posix', and PIC issues. */ + option `-posix', and PIC issues. Try to detect support for the + `long long' type. Unfortunately the GCC spec parser will not allow us + to properly detect the "iso9899:1990" and "iso9899:199409" forms of + -std=c89. Because of the ':' in the -std argument. :-( I have left + them in the spec as a place holder in hopes someone knows a way to make + the detection of them work. */ #define FBSD_CPP_SPEC " \ %(cpp_cpu) \ - %(cpp_arch) \ + %{fPIC|fpic|fPIE|fpie:-D__PIC__ -D__pic__} \ + %{!ansi:%{!std=c89:%{!std=iso9899.1990:%{!std=iso9899.199409:-D_LONGLONG}}}} \ %{posix:-D_POSIX_SOURCE}" -/* Provide a STARTFILE_SPEC appropriate for FreeBSD. Here we add - the magical crtbegin.o file (see crtstuff.c) which provides part - of the support for getting C++ file-scope static object constructed - before entering `main'. */ +/* Provide a STARTFILE_SPEC appropriate for FreeBSD. Here we add the magical + crtbegin.o file (see crtstuff.c) which provides part of the support for + getting C++ file-scope static object constructed before entering `main'. */ -#define FBSD_STARTFILE_SPEC \ - "%{!shared: \ - %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} \ - %{!p:%{profile:gcrt1.o%s} \ - %{!profile:crt1.o%s}}}} \ - crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}" - -/* Provide a ENDFILE_SPEC appropriate for FreeBSD. Here we tack on - the magical crtend.o file (see crtstuff.c) which provides part of - the support for getting C++ file-scope static object constructed - before entering `main', followed by a normal "finalizer" file, - `crtn.o'. */ - -#define FBSD_ENDFILE_SPEC \ - "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s" +#define FBSD_STARTFILE_SPEC "\ + %{!shared: \ + %{pg:gcrt1.o%s} \ + %{!pg: \ + %{p:gcrt1.o%s} \ + %{!p: \ + %{profile:gcrt1.o%s} \ + %{!profile:crt1.o%s}}}} \ + crti.o%s \ + %{!shared:crtbegin.o%s} \ + %{shared:crtbeginS.o%s}" + +/* Provide an ENDFILE_SPEC appropriate for FreeBSD/i386. Here we tack on + our own magical crtend.o file (see crtstuff.c) which provides part of + the support for getting C++ file-scope static object constructed before + entering `main', followed by the normal "finalizer" file, `crtn.o'. */ + +#define FBSD_ENDFILE_SPEC "\ + %{!shared:crtend.o%s} \ + %{shared:crtendS.o%s} \ + crtn.o%s " /* Provide a LIB_SPEC appropriate for FreeBSD as configured and as required by the user-land thread model. Before __FreeBSD_version @@ -109,7 +133,7 @@ Boston, MA 02110-1301, USA. */ /* Provide a LIB_SPEC appropriate for FreeBSD. Just select the appropriate libc, depending on whether we're doing profiling or need threads support. - (similar to the default, except no -lg, and no -p). */ + (simular to the default, except no -lg, and no -p). */ #ifdef FBSD_NO_THREADS #define FBSD_LIB_SPEC " \ @@ -120,7 +144,8 @@ is built with the --enable-threads configure-time option.} \ %{pg: -lc_p} \ }" #else -#if FBSD_MAJOR < 5 +#include <sys/param.h> +#if __FreeBSD_version < 500016 #define FBSD_LIB_SPEC " \ %{!shared: \ %{!pg: \ @@ -139,7 +164,7 @@ is built with the --enable-threads configure-time option.} \ #endif #endif -#if FBSD_MAJOR < 6 +#if FBSD_MAJOR < 5 #define FBSD_DYNAMIC_LINKER "/usr/libexec/ld-elf.so.1" #else #define FBSD_DYNAMIC_LINKER "/libexec/ld-elf.so.1" diff --git a/contrib/gcc/config/freebsd.h b/contrib/gcc/config/freebsd.h index 21dc81e..9a9ec96 100644 --- a/contrib/gcc/config/freebsd.h +++ b/contrib/gcc/config/freebsd.h @@ -1,5 +1,5 @@ /* Base configuration file for all FreeBSD targets. - Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GCC. @@ -15,8 +15,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* Common FreeBSD configuration. All FreeBSD architectures should include this file, which will specify @@ -26,6 +26,7 @@ Boston, MA 02110-1301, USA. */ Further work by David O'Brien <obrien@FreeBSD.org> and Loren J. Rittle <ljrittle@acm.org>. */ +/* $FreeBSD$ */ /* In case we need to know. */ #define USING_CONFIG_FREEBSD 1 @@ -61,7 +62,7 @@ Boston, MA 02110-1301, USA. */ /* All FreeBSD Architectures support the ELF object file format. */ #undef OBJECT_FORMAT_ELF -#define OBJECT_FORMAT_ELF +#define OBJECT_FORMAT_ELF 1 /* Don't assume anything about the header files. */ #undef NO_IMPLICIT_EXTERN_C @@ -72,10 +73,18 @@ Boston, MA 02110-1301, USA. */ #undef WCHAR_TYPE #define WCHAR_TYPE "int" +#ifdef FREEBSD_NATIVE +#define LIBSTDCXX_PROFILE "-lstdc++_p" +#endif #define MATH_LIBRARY_PROFILE "-lm_p" /* Code generation parameters. */ +/* Writing `int' for a bitfield forces int alignment for the structure. */ +/* XXX: ok for Alpha?? */ +#undef PCC_BITFIELD_TYPE_MATTERS +#define PCC_BITFIELD_TYPE_MATTERS 1 + /* Use periods rather than dollar signs in special g++ assembler names. This ensures the configuration knows our system correctly so we can link with libraries compiled with the native cc. */ @@ -84,4 +93,8 @@ Boston, MA 02110-1301, USA. */ /* Used by libgcc2.c. We support file locking with fcntl / F_SETLKW. This enables the test coverage code to use file locking when exiting a program, which avoids race conditions if the program has forked. */ -#define TARGET_POSIX_IO +#define TARGET_HAS_F_SETLKW 1 + +/* Define this so we can compile MS code for use with WINE. */ +#define HANDLE_PRAGMA_PACK_PUSH_POP + diff --git a/contrib/gcc/config/i386/freebsd.h b/contrib/gcc/config/i386/freebsd.h index deb9212..1bfde2f 100644 --- a/contrib/gcc/config/i386/freebsd.h +++ b/contrib/gcc/config/i386/freebsd.h @@ -1,5 +1,5 @@ /* Definitions for Intel 386 running FreeBSD with ELF format - Copyright (C) 1996, 2000, 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 1996, 2000, 2002 Free Software Foundation, Inc. Contributed by Eric Youngdale. Modified for stabs-in-ELF by H.J. Lu. Adapted from GNU/Linux version by John Polstra. @@ -19,113 +19,89 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +/* $FreeBSD$ */ -#define TARGET_VERSION fprintf (stderr, " (i386 FreeBSD/ELF)"); +#undef CC1_SPEC +#define CC1_SPEC "%(cc1_cpu) %{profile:-p}" -/* Override the default comment-starter of "/". */ -#undef ASM_COMMENT_START -#define ASM_COMMENT_START "#" +#undef ASM_SPEC +#define ASM_SPEC "%{v*: -v}" -#undef ASM_APP_ON -#define ASM_APP_ON "#APP\n" +/* Provide a LINK_SPEC appropriate for FreeBSD. Here we provide support + for the special GCC options -static and -shared, which allow us to + link things in one of these three modes by applying the appropriate + combinations of options at link-time. We like to support here for + as many of the other GNU linker options as possible. But I don't + have the time to search for those flags. I am sure how to add + support for -soname shared_object_name. H.J. -#undef ASM_APP_OFF -#define ASM_APP_OFF "#NO_APP\n" + When the -shared link option is used a final link is not being + done. */ -#undef DBX_REGISTER_NUMBER -#define DBX_REGISTER_NUMBER(n) \ - (TARGET_64BIT ? dbx64_register_map[n] : svr4_dbx_register_map[n]) +#undef LINK_SPEC +#define LINK_SPEC "\ + %{p:%nconsider using `-pg' instead of `-p' with gprof(1) } \ + %{Wl,*:%*} \ + %{v:-V} \ + %{assert*} %{R*} %{rpath*} %{defsym*} \ + %{shared:-Bshareable %{h*} %{soname*}} \ + %{!shared: \ + %{!static: \ + %{rdynamic: -export-dynamic} \ + %{!dynamic-linker:-dynamic-linker %(fbsd_dynamic_linker) }} \ + %{static:-Bstatic}} \ + %{symbolic:-Bsymbolic}" -#undef NO_PROFILE_COUNTERS -#define NO_PROFILE_COUNTERS 1 +/* Reset our STARTFILE_SPEC which was properly set in config/freebsd.h + but trashed by config/<cpu>/<file.h>. */ -/* Tell final.c that we don't need a label passed to mcount. */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC FBSD_STARTFILE_SPEC -#undef MCOUNT_NAME -#define MCOUNT_NAME ".mcount" +/* Provide an ENDFILE_SPEC appropriate for FreeBSD/i386. */ + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC FBSD_ENDFILE_SPEC -/* Make gcc agree with <machine/ansi.h>. */ + +/************************[ Target stuff ]***********************************/ + +/* Define the actual types of some ANSI-mandated types. + Needs to agree with <machine/ansi.h>. GCC defaults come from c-decl.c, + c-common.c, and config/<arch>/<arch>.h. */ #undef SIZE_TYPE #define SIZE_TYPE (TARGET_64BIT ? "long unsigned int" : "unsigned int") - + #undef PTRDIFF_TYPE #define PTRDIFF_TYPE (TARGET_64BIT ? "long int" : "int") - + #undef WCHAR_TYPE_SIZE #define WCHAR_TYPE_SIZE (TARGET_64BIT ? 32 : BITS_PER_WORD) -#undef SUBTARGET_EXTRA_SPECS /* i386.h bogusly defines it. */ +#undef SUBTARGET_EXTRA_SPECS /* i386.h bogusly defines it. */ #define SUBTARGET_EXTRA_SPECS \ { "fbsd_dynamic_linker", FBSD_DYNAMIC_LINKER } - -/* Provide a STARTFILE_SPEC appropriate for FreeBSD. Here we add - the magical crtbegin.o file (see crtstuff.c) which provides part - of the support for getting C++ file-scope static object constructed - before entering `main'. */ - -#undef STARTFILE_SPEC -#define STARTFILE_SPEC \ - "%{!shared: \ - %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} \ - %{!p:%{profile:gcrt1.o%s} \ - %{!profile:crt1.o%s}}}} \ - crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}" - -/* Provide a ENDFILE_SPEC appropriate for FreeBSD. Here we tack on - the magical crtend.o file (see crtstuff.c) which provides part of - the support for getting C++ file-scope static object constructed - before entering `main', followed by a normal "finalizer" file, - `crtn.o'. */ - -#undef ENDFILE_SPEC -#define ENDFILE_SPEC \ - "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s" - -/* Provide a LINK_SPEC appropriate for FreeBSD. Here we provide support - for the special GCC options -static and -shared, which allow us to - link things in one of these three modes by applying the appropriate - combinations of options at link-time. We like to support here for - as many of the other GNU linker options as possible. But I don't - have the time to search for those flags. I am sure how to add - support for -soname shared_object_name. H.J. - I took out %{v:%{!V:-V}}. It is too much :-(. They can use - -Wl,-V. +#define TARGET_VERSION fprintf (stderr, " (i386 FreeBSD/ELF)"); - When the -shared link option is used a final link is not being - done. */ +#define MASK_PROFILER_EPILOGUE 010000000000 -#undef LINK_SPEC -#define LINK_SPEC "\ - %{p:%nconsider using `-pg' instead of `-p' with gprof(1)} \ - %{v:-V} \ - %{assert*} %{R*} %{rpath*} %{defsym*} \ - %{shared:-Bshareable %{h*} %{soname*}} \ - %{!shared: \ - %{!static: \ - %{rdynamic:-export-dynamic} \ - %{!dynamic-linker:-dynamic-linker %(fbsd_dynamic_linker) }} \ - %{static:-Bstatic}} \ - %{symbolic:-Bsymbolic}" - -/* A C statement to output to the stdio stream FILE an assembler - command to advance the location counter to a multiple of 1<<LOG - bytes if it is within MAX_SKIP bytes. +#define TARGET_PROFILER_EPILOGUE (target_flags & MASK_PROFILER_EPILOGUE) +#define TARGET_ELF 1 - This is used to align code labels according to Intel recommendations. */ +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ + { "profiler-epilogue", MASK_PROFILER_EPILOGUE, "Function profiler epilogue"}, \ + { "no-profiler-epilogue", -MASK_PROFILER_EPILOGUE, "No function profiler epilogue"}, -#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN -#undef ASM_OUTPUT_MAX_SKIP_ALIGN -#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE, LOG, MAX_SKIP) \ - if ((LOG) != 0) { \ - if ((MAX_SKIP) == 0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \ - else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \ - } -#endif +/* This goes away when the math emulator is fixed. */ +#undef TARGET_SUBTARGET_DEFAULT +#define TARGET_SUBTARGET_DEFAULT \ + (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_NO_FANCY_MATH_387) /* Don't default to pcc-struct-return, we want to retain compatibility with older gcc versions AND pcc-struct-return is nonreentrant. @@ -139,3 +115,156 @@ Boston, MA 02110-1301, USA. */ compiler get the contents of <float.h> and std::numeric_limits correct. */ #undef TARGET_96_ROUND_53_LONG_DOUBLE #define TARGET_96_ROUND_53_LONG_DOUBLE (!TARGET_64BIT) + +/* Tell final.c that we don't need a label passed to mcount. */ +#define NO_PROFILE_COUNTERS 1 + +/* Output assembler code to FILE to begin profiling of the current function. + LABELNO is an optional label. */ + +#undef MCOUNT_NAME +#define MCOUNT_NAME ".mcount" + +/* Output assembler code to FILE to end profiling of the current function. */ + +#undef FUNCTION_PROFILER_EPILOGUE /* BDE will need to fix this. */ + + +/************************[ Assembler stuff ]********************************/ + +/* Override the default comment-starter of "/" from unix.h. */ +#undef ASM_COMMENT_START +#define ASM_COMMENT_START "#" + +/* Override the default comment-starter of "/APP" from unix.h. */ +#undef ASM_APP_ON +#define ASM_APP_ON "#APP\n" +#undef ASM_APP_OFF +#define ASM_APP_OFF "#NO_APP\n" + +/* XXX:DEO do we still need this override to defaults.h ?? */ +/* This is how to output a reference to a user-level label named NAME. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE, NAME) \ + do { \ + const char *xname = (NAME); \ + /* Hack to avoid writing lots of rtl in \ + FUNCTION_PROFILER_EPILOGUE (). */ \ + if (*xname == '.' && strcmp(xname + 1, "mexitcount") == 0) \ + { \ + if (flag_pic) \ + fprintf ((FILE), "*%s@GOT(%%ebx)", xname); \ + else \ + fprintf ((FILE), "%s", xname); \ + } \ + else \ + { \ + if (xname[0] == '%') \ + xname += 2; \ + if (xname[0] == '*') \ + xname += 1; \ + else \ + fputs (user_label_prefix, FILE); \ + fputs (xname, FILE); \ + } \ +} while (0) + +/* This is how to hack on the symbol code of certain relcalcitrant + symbols to modify their output in output_pic_addr_const (). */ + +#undef ASM_HACK_SYMBOLREF_CODE /* BDE will need to fix this. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE, LOG) \ + do { \ + if ((LOG)!=0) { \ + if (in_text_section()) \ + fprintf ((FILE), "\t.p2align %d,0x90\n", (LOG)); \ + else \ + fprintf ((FILE), "\t.p2align %d\n", (LOG)); \ + } \ + } while (0) + +/* A C statement to output to the stdio stream FILE an assembler + command to advance the location counter to a multiple of 1<<LOG + bytes if it is within MAX_SKIP bytes. + + This is used to align code labels according to Intel recommendations. */ + +/* XXX configuration of this is broken in the same way as HAVE_GAS_SHF_MERGE, + but it is easier to fix in an MD way. */ + +#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN +#undef ASM_OUTPUT_MAX_SKIP_ALIGN +#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE, LOG, MAX_SKIP) \ + do { \ + if ((LOG) != 0) { \ + if ((MAX_SKIP) == 0) \ + fprintf ((FILE), "\t.p2align %d\n", (LOG)); \ + else \ + fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \ + } \ + } while (0) +#endif + +/* If defined, a C expression whose value is a string containing the + assembler operation to identify the following data as + uninitialized global data. If not defined, and neither + `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined, + uninitialized global data will be output in the data section if + `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be + used. */ +#undef BSS_SECTION_ASM_OP +#define BSS_SECTION_ASM_OP "\t.section\t.bss" + +/* Like `ASM_OUTPUT_BSS' except takes the required alignment as a + separate, explicit argument. If you define this macro, it is used + in place of `ASM_OUTPUT_BSS', and gives you more flexibility in + handling the required alignment of the variable. The alignment is + specified as the number of bits. + + Try to use function `asm_output_aligned_bss' defined in file + `varasm.c' when defining this macro. */ +#undef ASM_OUTPUT_ALIGNED_BSS +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ + asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) + +/************************[ Debugger stuff ]*********************************/ + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) (TARGET_64BIT ? dbx64_register_map[n] \ + : (write_symbols == DWARF2_DEBUG \ + || write_symbols == DWARF_DEBUG) \ + ? svr4_dbx_register_map[(n)] \ + : dbx_register_map[(n)]) + +/* The same functions are used to creating the DWARF2 debug info and C++ + unwind info (except.c). Regardless of the debug format requested, the + register numbers used in exception unwinding sections still have to be + DWARF compatible. IMO the GCC folks may be abusing the DBX_REGISTER_NUMBER + macro to mean too much. */ +#define DWARF_FRAME_REGNUM(n) (TARGET_64BIT ? dbx64_register_map[n] \ + : svr4_dbx_register_map[(n)]) + +/* stabs-in-elf has offsets relative to function beginning */ +#undef DBX_OUTPUT_LBRAC +#define DBX_OUTPUT_LBRAC(FILE, NAME) \ + do { \ + fprintf (asmfile, "%s %d,0,0,", ASM_STABN_OP, N_LBRAC); \ + assemble_name (asmfile, NAME); \ + fputc ('-', asmfile); \ + assemble_name (asmfile, \ + XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); \ + fprintf (asmfile, "\n"); \ + } while (0) + +#undef DBX_OUTPUT_RBRAC +#define DBX_OUTPUT_RBRAC(FILE, NAME) \ + do { \ + fprintf (asmfile, "%s %d,0,0,", ASM_STABN_OP, N_RBRAC); \ + assemble_name (asmfile, NAME); \ + fputc ('-', asmfile); \ + assemble_name (asmfile, \ + XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); \ + fprintf (asmfile, "\n"); \ + } while (0) diff --git a/contrib/gcc/config/i386/freebsd64.h b/contrib/gcc/config/i386/freebsd64.h index 257bdd9..473ef2f 100644 --- a/contrib/gcc/config/i386/freebsd64.h +++ b/contrib/gcc/config/i386/freebsd64.h @@ -1,5 +1,5 @@ /* Definitions for AMD x86-64 running FreeBSD with ELF format - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002 Free Software Foundation, Inc. Contributed by David O'Brien <obrien@FreeBSD.org> This file is part of GCC. @@ -16,13 +16,26 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* $FreeBSD$ */ #undef TARGET_VERSION #define TARGET_VERSION fprintf (stderr, " (FreeBSD/x86-64 ELF)"); +#undef FBSD_TARGET_CPU_CPP_BUILTINS +#define FBSD_TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + if (TARGET_64BIT) \ + { \ + builtin_define ("__LP64__"); \ + } \ + } \ + while (0) + #define SUBTARGET_EXTRA_SPECS \ { "fbsd_dynamic_linker", FBSD_DYNAMIC_LINKER } @@ -33,6 +46,7 @@ Boston, MA 02110-1301, USA. */ #undef LINK_SPEC #define LINK_SPEC "\ %{m32:-m elf_i386_fbsd} \ + %{Wl,*:%*} \ %{v:-V} \ %{assert*} %{R*} %{rpath*} %{defsym*} \ %{shared:-Bshareable %{h*} %{soname*}} \ diff --git a/contrib/gcc/config/i386/i386.c b/contrib/gcc/config/i386/i386.c index 29afed7..0360ff1 100644 --- a/contrib/gcc/config/i386/i386.c +++ b/contrib/gcc/config/i386/i386.c @@ -1,6 +1,6 @@ /* Subroutines used for code generation on IA-32. Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,12 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* $FreeBSD$ */ + #include "config.h" #include "system.h" @@ -32,7 +36,6 @@ Boston, MA 02110-1301, USA. */ #include "insn-config.h" #include "conditions.h" #include "output.h" -#include "insn-codes.h" #include "insn-attr.h" #include "flags.h" #include "except.h" @@ -47,9 +50,6 @@ Boston, MA 02110-1301, USA. */ #include "target-def.h" #include "langhooks.h" #include "cgraph.h" -#include "tree-gimple.h" -#include "dwarf2.h" -#include "tm-constrs.h" #ifndef CHECK_STACK_LIMIT #define CHECK_STACK_LIMIT (-1) @@ -64,28 +64,17 @@ Boston, MA 02110-1301, USA. */ : 4) /* Processor costs (relative to an add) */ -/* We assume COSTS_N_INSNS is defined as (N)*4 and an addition is 2 bytes. */ -#define COSTS_N_BYTES(N) ((N) * 2) - static const -struct processor_costs size_cost = { /* costs for tuning for size */ - COSTS_N_BYTES (2), /* cost of an add instruction */ - COSTS_N_BYTES (3), /* cost of a lea instruction */ - COSTS_N_BYTES (2), /* variable shift costs */ - COSTS_N_BYTES (3), /* constant shift costs */ - {COSTS_N_BYTES (3), /* cost of starting multiply for QI */ - COSTS_N_BYTES (3), /* HI */ - COSTS_N_BYTES (3), /* SI */ - COSTS_N_BYTES (3), /* DI */ - COSTS_N_BYTES (5)}, /* other */ +struct processor_costs size_cost = { /* costs for tunning for size */ + 2, /* cost of an add instruction */ + 3, /* cost of a lea instruction */ + 2, /* variable shift costs */ + 3, /* constant shift costs */ + {3, 3, 3, 3, 5}, /* cost of starting a multiply */ 0, /* cost of multiply per each bit set */ - {COSTS_N_BYTES (3), /* cost of a divide/mod for QI */ - COSTS_N_BYTES (3), /* HI */ - COSTS_N_BYTES (3), /* SI */ - COSTS_N_BYTES (3), /* DI */ - COSTS_N_BYTES (5)}, /* other */ - COSTS_N_BYTES (3), /* cost of movsx */ - COSTS_N_BYTES (3), /* cost of movzx */ + {3, 3, 3, 3, 5}, /* cost of a divide/mod */ + 3, /* cost of movsx */ + 3, /* cost of movzx */ 0, /* "large" insn */ 2, /* MOVE_RATIO */ 2, /* cost for loading QImode using movzbl */ @@ -96,8 +85,7 @@ struct processor_costs size_cost = { /* costs for tuning for size */ 2, /* cost of reg,reg fld/fst */ {2, 2, 2}, /* cost of loading fp registers in SFmode, DFmode and XFmode */ - {2, 2, 2}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ + {2, 2, 2}, /* cost of loading integer registers */ 3, /* cost of moving MMX register */ {3, 3}, /* cost of loading MMX registers in SImode and DImode */ @@ -111,35 +99,27 @@ struct processor_costs size_cost = { /* costs for tuning for size */ 3, /* MMX or SSE register to integer */ 0, /* size of prefetch block */ 0, /* number of parallel prefetches */ - 2, /* Branch cost */ - COSTS_N_BYTES (2), /* cost of FADD and FSUB insns. */ - COSTS_N_BYTES (2), /* cost of FMUL instruction. */ - COSTS_N_BYTES (2), /* cost of FDIV instruction. */ - COSTS_N_BYTES (2), /* cost of FABS instruction. */ - COSTS_N_BYTES (2), /* cost of FCHS instruction. */ - COSTS_N_BYTES (2), /* cost of FSQRT instruction. */ + 1, /* Branch cost */ + 2, /* cost of FADD and FSUB insns. */ + 2, /* cost of FMUL instruction. */ + 2, /* cost of FDIV instruction. */ + 2, /* cost of FABS instruction. */ + 2, /* cost of FCHS instruction. */ + 2, /* cost of FSQRT instruction. */ }; /* Processor costs (relative to an add) */ static const struct processor_costs i386_cost = { /* 386 specific costs */ - COSTS_N_INSNS (1), /* cost of an add instruction */ - COSTS_N_INSNS (1), /* cost of a lea instruction */ - COSTS_N_INSNS (3), /* variable shift costs */ - COSTS_N_INSNS (2), /* constant shift costs */ - {COSTS_N_INSNS (6), /* cost of starting multiply for QI */ - COSTS_N_INSNS (6), /* HI */ - COSTS_N_INSNS (6), /* SI */ - COSTS_N_INSNS (6), /* DI */ - COSTS_N_INSNS (6)}, /* other */ - COSTS_N_INSNS (1), /* cost of multiply per each bit set */ - {COSTS_N_INSNS (23), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (23), /* HI */ - COSTS_N_INSNS (23), /* SI */ - COSTS_N_INSNS (23), /* DI */ - COSTS_N_INSNS (23)}, /* other */ - COSTS_N_INSNS (3), /* cost of movsx */ - COSTS_N_INSNS (2), /* cost of movzx */ + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 3, /* variable shift costs */ + 2, /* constant shift costs */ + {6, 6, 6, 6, 6}, /* cost of starting a multiply */ + 1, /* cost of multiply per each bit set */ + {23, 23, 23, 23, 23}, /* cost of a divide/mod */ + 3, /* cost of movsx */ + 2, /* cost of movzx */ 15, /* "large" insn */ 3, /* MOVE_RATIO */ 4, /* cost for loading QImode using movzbl */ @@ -150,8 +130,7 @@ struct processor_costs i386_cost = { /* 386 specific costs */ 2, /* cost of reg,reg fld/fst */ {8, 8, 8}, /* cost of loading fp registers in SFmode, DFmode and XFmode */ - {8, 8, 8}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ + {8, 8, 8}, /* cost of loading integer registers */ 2, /* cost of moving MMX register */ {4, 8}, /* cost of loading MMX registers in SImode and DImode */ @@ -166,33 +145,25 @@ struct processor_costs i386_cost = { /* 386 specific costs */ 0, /* size of prefetch block */ 0, /* number of parallel prefetches */ 1, /* Branch cost */ - COSTS_N_INSNS (23), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (27), /* cost of FMUL instruction. */ - COSTS_N_INSNS (88), /* cost of FDIV instruction. */ - COSTS_N_INSNS (22), /* cost of FABS instruction. */ - COSTS_N_INSNS (24), /* cost of FCHS instruction. */ - COSTS_N_INSNS (122), /* cost of FSQRT instruction. */ + 23, /* cost of FADD and FSUB insns. */ + 27, /* cost of FMUL instruction. */ + 88, /* cost of FDIV instruction. */ + 22, /* cost of FABS instruction. */ + 24, /* cost of FCHS instruction. */ + 122, /* cost of FSQRT instruction. */ }; static const struct processor_costs i486_cost = { /* 486 specific costs */ - COSTS_N_INSNS (1), /* cost of an add instruction */ - COSTS_N_INSNS (1), /* cost of a lea instruction */ - COSTS_N_INSNS (3), /* variable shift costs */ - COSTS_N_INSNS (2), /* constant shift costs */ - {COSTS_N_INSNS (12), /* cost of starting multiply for QI */ - COSTS_N_INSNS (12), /* HI */ - COSTS_N_INSNS (12), /* SI */ - COSTS_N_INSNS (12), /* DI */ - COSTS_N_INSNS (12)}, /* other */ + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 3, /* variable shift costs */ + 2, /* constant shift costs */ + {12, 12, 12, 12, 12}, /* cost of starting a multiply */ 1, /* cost of multiply per each bit set */ - {COSTS_N_INSNS (40), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (40), /* HI */ - COSTS_N_INSNS (40), /* SI */ - COSTS_N_INSNS (40), /* DI */ - COSTS_N_INSNS (40)}, /* other */ - COSTS_N_INSNS (3), /* cost of movsx */ - COSTS_N_INSNS (2), /* cost of movzx */ + {40, 40, 40, 40, 40}, /* cost of a divide/mod */ + 3, /* cost of movsx */ + 2, /* cost of movzx */ 15, /* "large" insn */ 3, /* MOVE_RATIO */ 4, /* cost for loading QImode using movzbl */ @@ -203,8 +174,7 @@ struct processor_costs i486_cost = { /* 486 specific costs */ 2, /* cost of reg,reg fld/fst */ {8, 8, 8}, /* cost of loading fp registers in SFmode, DFmode and XFmode */ - {8, 8, 8}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ + {8, 8, 8}, /* cost of loading integer registers */ 2, /* cost of moving MMX register */ {4, 8}, /* cost of loading MMX registers in SImode and DImode */ @@ -219,33 +189,25 @@ struct processor_costs i486_cost = { /* 486 specific costs */ 0, /* size of prefetch block */ 0, /* number of parallel prefetches */ 1, /* Branch cost */ - COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (16), /* cost of FMUL instruction. */ - COSTS_N_INSNS (73), /* cost of FDIV instruction. */ - COSTS_N_INSNS (3), /* cost of FABS instruction. */ - COSTS_N_INSNS (3), /* cost of FCHS instruction. */ - COSTS_N_INSNS (83), /* cost of FSQRT instruction. */ + 8, /* cost of FADD and FSUB insns. */ + 16, /* cost of FMUL instruction. */ + 73, /* cost of FDIV instruction. */ + 3, /* cost of FABS instruction. */ + 3, /* cost of FCHS instruction. */ + 83, /* cost of FSQRT instruction. */ }; static const struct processor_costs pentium_cost = { - COSTS_N_INSNS (1), /* cost of an add instruction */ - COSTS_N_INSNS (1), /* cost of a lea instruction */ - COSTS_N_INSNS (4), /* variable shift costs */ - COSTS_N_INSNS (1), /* constant shift costs */ - {COSTS_N_INSNS (11), /* cost of starting multiply for QI */ - COSTS_N_INSNS (11), /* HI */ - COSTS_N_INSNS (11), /* SI */ - COSTS_N_INSNS (11), /* DI */ - COSTS_N_INSNS (11)}, /* other */ + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 4, /* variable shift costs */ + 1, /* constant shift costs */ + {11, 11, 11, 11, 11}, /* cost of starting a multiply */ 0, /* cost of multiply per each bit set */ - {COSTS_N_INSNS (25), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (25), /* HI */ - COSTS_N_INSNS (25), /* SI */ - COSTS_N_INSNS (25), /* DI */ - COSTS_N_INSNS (25)}, /* other */ - COSTS_N_INSNS (3), /* cost of movsx */ - COSTS_N_INSNS (2), /* cost of movzx */ + {25, 25, 25, 25, 25}, /* cost of a divide/mod */ + 3, /* cost of movsx */ + 2, /* cost of movzx */ 8, /* "large" insn */ 6, /* MOVE_RATIO */ 6, /* cost for loading QImode using movzbl */ @@ -256,8 +218,7 @@ struct processor_costs pentium_cost = { 2, /* cost of reg,reg fld/fst */ {2, 2, 6}, /* cost of loading fp registers in SFmode, DFmode and XFmode */ - {4, 4, 6}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ + {4, 4, 6}, /* cost of loading integer registers */ 8, /* cost of moving MMX register */ {8, 8}, /* cost of loading MMX registers in SImode and DImode */ @@ -272,33 +233,25 @@ struct processor_costs pentium_cost = { 0, /* size of prefetch block */ 0, /* number of parallel prefetches */ 2, /* Branch cost */ - COSTS_N_INSNS (3), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (3), /* cost of FMUL instruction. */ - COSTS_N_INSNS (39), /* cost of FDIV instruction. */ - COSTS_N_INSNS (1), /* cost of FABS instruction. */ - COSTS_N_INSNS (1), /* cost of FCHS instruction. */ - COSTS_N_INSNS (70), /* cost of FSQRT instruction. */ + 3, /* cost of FADD and FSUB insns. */ + 3, /* cost of FMUL instruction. */ + 39, /* cost of FDIV instruction. */ + 1, /* cost of FABS instruction. */ + 1, /* cost of FCHS instruction. */ + 70, /* cost of FSQRT instruction. */ }; static const struct processor_costs pentiumpro_cost = { - COSTS_N_INSNS (1), /* cost of an add instruction */ - COSTS_N_INSNS (1), /* cost of a lea instruction */ - COSTS_N_INSNS (1), /* variable shift costs */ - COSTS_N_INSNS (1), /* constant shift costs */ - {COSTS_N_INSNS (4), /* cost of starting multiply for QI */ - COSTS_N_INSNS (4), /* HI */ - COSTS_N_INSNS (4), /* SI */ - COSTS_N_INSNS (4), /* DI */ - COSTS_N_INSNS (4)}, /* other */ + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 1, /* variable shift costs */ + 1, /* constant shift costs */ + {4, 4, 4, 4, 4}, /* cost of starting a multiply */ 0, /* cost of multiply per each bit set */ - {COSTS_N_INSNS (17), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (17), /* HI */ - COSTS_N_INSNS (17), /* SI */ - COSTS_N_INSNS (17), /* DI */ - COSTS_N_INSNS (17)}, /* other */ - COSTS_N_INSNS (1), /* cost of movsx */ - COSTS_N_INSNS (1), /* cost of movzx */ + {17, 17, 17, 17, 17}, /* cost of a divide/mod */ + 1, /* cost of movsx */ + 1, /* cost of movzx */ 8, /* "large" insn */ 6, /* MOVE_RATIO */ 2, /* cost for loading QImode using movzbl */ @@ -309,8 +262,7 @@ struct processor_costs pentiumpro_cost = { 2, /* cost of reg,reg fld/fst */ {2, 2, 6}, /* cost of loading fp registers in SFmode, DFmode and XFmode */ - {4, 4, 6}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ + {4, 4, 6}, /* cost of loading integer registers */ 2, /* cost of moving MMX register */ {2, 2}, /* cost of loading MMX registers in SImode and DImode */ @@ -325,33 +277,25 @@ struct processor_costs pentiumpro_cost = { 32, /* size of prefetch block */ 6, /* number of parallel prefetches */ 2, /* Branch cost */ - COSTS_N_INSNS (3), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (5), /* cost of FMUL instruction. */ - COSTS_N_INSNS (56), /* cost of FDIV instruction. */ - COSTS_N_INSNS (2), /* cost of FABS instruction. */ - COSTS_N_INSNS (2), /* cost of FCHS instruction. */ - COSTS_N_INSNS (56), /* cost of FSQRT instruction. */ + 3, /* cost of FADD and FSUB insns. */ + 5, /* cost of FMUL instruction. */ + 56, /* cost of FDIV instruction. */ + 2, /* cost of FABS instruction. */ + 2, /* cost of FCHS instruction. */ + 56, /* cost of FSQRT instruction. */ }; static const struct processor_costs k6_cost = { - COSTS_N_INSNS (1), /* cost of an add instruction */ - COSTS_N_INSNS (2), /* cost of a lea instruction */ - COSTS_N_INSNS (1), /* variable shift costs */ - COSTS_N_INSNS (1), /* constant shift costs */ - {COSTS_N_INSNS (3), /* cost of starting multiply for QI */ - COSTS_N_INSNS (3), /* HI */ - COSTS_N_INSNS (3), /* SI */ - COSTS_N_INSNS (3), /* DI */ - COSTS_N_INSNS (3)}, /* other */ + 1, /* cost of an add instruction */ + 2, /* cost of a lea instruction */ + 1, /* variable shift costs */ + 1, /* constant shift costs */ + {3, 3, 3, 3, 3}, /* cost of starting a multiply */ 0, /* cost of multiply per each bit set */ - {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (18), /* HI */ - COSTS_N_INSNS (18), /* SI */ - COSTS_N_INSNS (18), /* DI */ - COSTS_N_INSNS (18)}, /* other */ - COSTS_N_INSNS (2), /* cost of movsx */ - COSTS_N_INSNS (2), /* cost of movzx */ + {18, 18, 18, 18, 18}, /* cost of a divide/mod */ + 2, /* cost of movsx */ + 2, /* cost of movzx */ 8, /* "large" insn */ 4, /* MOVE_RATIO */ 3, /* cost for loading QImode using movzbl */ @@ -362,8 +306,7 @@ struct processor_costs k6_cost = { 4, /* cost of reg,reg fld/fst */ {6, 6, 6}, /* cost of loading fp registers in SFmode, DFmode and XFmode */ - {4, 4, 4}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ + {4, 4, 4}, /* cost of loading integer registers */ 2, /* cost of moving MMX register */ {2, 2}, /* cost of loading MMX registers in SImode and DImode */ @@ -378,33 +321,25 @@ struct processor_costs k6_cost = { 32, /* size of prefetch block */ 1, /* number of parallel prefetches */ 1, /* Branch cost */ - COSTS_N_INSNS (2), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (2), /* cost of FMUL instruction. */ - COSTS_N_INSNS (56), /* cost of FDIV instruction. */ - COSTS_N_INSNS (2), /* cost of FABS instruction. */ - COSTS_N_INSNS (2), /* cost of FCHS instruction. */ - COSTS_N_INSNS (56), /* cost of FSQRT instruction. */ + 2, /* cost of FADD and FSUB insns. */ + 2, /* cost of FMUL instruction. */ + 56, /* cost of FDIV instruction. */ + 2, /* cost of FABS instruction. */ + 2, /* cost of FCHS instruction. */ + 56, /* cost of FSQRT instruction. */ }; static const struct processor_costs athlon_cost = { - COSTS_N_INSNS (1), /* cost of an add instruction */ - COSTS_N_INSNS (2), /* cost of a lea instruction */ - COSTS_N_INSNS (1), /* variable shift costs */ - COSTS_N_INSNS (1), /* constant shift costs */ - {COSTS_N_INSNS (5), /* cost of starting multiply for QI */ - COSTS_N_INSNS (5), /* HI */ - COSTS_N_INSNS (5), /* SI */ - COSTS_N_INSNS (5), /* DI */ - COSTS_N_INSNS (5)}, /* other */ + 1, /* cost of an add instruction */ + 2, /* cost of a lea instruction */ + 1, /* variable shift costs */ + 1, /* constant shift costs */ + {5, 5, 5, 5, 5}, /* cost of starting a multiply */ 0, /* cost of multiply per each bit set */ - {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (26), /* HI */ - COSTS_N_INSNS (42), /* SI */ - COSTS_N_INSNS (74), /* DI */ - COSTS_N_INSNS (74)}, /* other */ - COSTS_N_INSNS (1), /* cost of movsx */ - COSTS_N_INSNS (1), /* cost of movzx */ + {18, 26, 42, 74, 74}, /* cost of a divide/mod */ + 1, /* cost of movsx */ + 1, /* cost of movzx */ 8, /* "large" insn */ 9, /* MOVE_RATIO */ 4, /* cost for loading QImode using movzbl */ @@ -415,8 +350,7 @@ struct processor_costs athlon_cost = { 4, /* cost of reg,reg fld/fst */ {4, 4, 12}, /* cost of loading fp registers in SFmode, DFmode and XFmode */ - {6, 6, 8}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ + {6, 6, 8}, /* cost of loading integer registers */ 2, /* cost of moving MMX register */ {4, 4}, /* cost of loading MMX registers in SImode and DImode */ @@ -430,34 +364,26 @@ struct processor_costs athlon_cost = { 5, /* MMX or SSE register to integer */ 64, /* size of prefetch block */ 6, /* number of parallel prefetches */ - 5, /* Branch cost */ - COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (4), /* cost of FMUL instruction. */ - COSTS_N_INSNS (24), /* cost of FDIV instruction. */ - COSTS_N_INSNS (2), /* cost of FABS instruction. */ - COSTS_N_INSNS (2), /* cost of FCHS instruction. */ - COSTS_N_INSNS (35), /* cost of FSQRT instruction. */ + 2, /* Branch cost */ + 4, /* cost of FADD and FSUB insns. */ + 4, /* cost of FMUL instruction. */ + 24, /* cost of FDIV instruction. */ + 2, /* cost of FABS instruction. */ + 2, /* cost of FCHS instruction. */ + 35, /* cost of FSQRT instruction. */ }; static const struct processor_costs k8_cost = { - COSTS_N_INSNS (1), /* cost of an add instruction */ - COSTS_N_INSNS (2), /* cost of a lea instruction */ - COSTS_N_INSNS (1), /* variable shift costs */ - COSTS_N_INSNS (1), /* constant shift costs */ - {COSTS_N_INSNS (3), /* cost of starting multiply for QI */ - COSTS_N_INSNS (4), /* HI */ - COSTS_N_INSNS (3), /* SI */ - COSTS_N_INSNS (4), /* DI */ - COSTS_N_INSNS (5)}, /* other */ + 1, /* cost of an add instruction */ + 2, /* cost of a lea instruction */ + 1, /* variable shift costs */ + 1, /* constant shift costs */ + {3, 4, 3, 4, 5}, /* cost of starting a multiply */ 0, /* cost of multiply per each bit set */ - {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (26), /* HI */ - COSTS_N_INSNS (42), /* SI */ - COSTS_N_INSNS (74), /* DI */ - COSTS_N_INSNS (74)}, /* other */ - COSTS_N_INSNS (1), /* cost of movsx */ - COSTS_N_INSNS (1), /* cost of movzx */ + {18, 26, 42, 74, 74}, /* cost of a divide/mod */ + 1, /* cost of movsx */ + 1, /* cost of movzx */ 8, /* "large" insn */ 9, /* MOVE_RATIO */ 4, /* cost for loading QImode using movzbl */ @@ -468,8 +394,7 @@ struct processor_costs k8_cost = { 4, /* cost of reg,reg fld/fst */ {4, 4, 12}, /* cost of loading fp registers in SFmode, DFmode and XFmode */ - {6, 6, 8}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ + {6, 6, 8}, /* cost of loading integer registers */ 2, /* cost of moving MMX register */ {3, 3}, /* cost of loading MMX registers in SImode and DImode */ @@ -483,34 +408,26 @@ struct processor_costs k8_cost = { 5, /* MMX or SSE register to integer */ 64, /* size of prefetch block */ 6, /* number of parallel prefetches */ - 5, /* Branch cost */ - COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (4), /* cost of FMUL instruction. */ - COSTS_N_INSNS (19), /* cost of FDIV instruction. */ - COSTS_N_INSNS (2), /* cost of FABS instruction. */ - COSTS_N_INSNS (2), /* cost of FCHS instruction. */ - COSTS_N_INSNS (35), /* cost of FSQRT instruction. */ + 2, /* Branch cost */ + 4, /* cost of FADD and FSUB insns. */ + 4, /* cost of FMUL instruction. */ + 19, /* cost of FDIV instruction. */ + 2, /* cost of FABS instruction. */ + 2, /* cost of FCHS instruction. */ + 35, /* cost of FSQRT instruction. */ }; static const struct processor_costs pentium4_cost = { - COSTS_N_INSNS (1), /* cost of an add instruction */ - COSTS_N_INSNS (3), /* cost of a lea instruction */ - COSTS_N_INSNS (4), /* variable shift costs */ - COSTS_N_INSNS (4), /* constant shift costs */ - {COSTS_N_INSNS (15), /* cost of starting multiply for QI */ - COSTS_N_INSNS (15), /* HI */ - COSTS_N_INSNS (15), /* SI */ - COSTS_N_INSNS (15), /* DI */ - COSTS_N_INSNS (15)}, /* other */ + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 4, /* variable shift costs */ + 4, /* constant shift costs */ + {15, 15, 15, 15, 15}, /* cost of starting a multiply */ 0, /* cost of multiply per each bit set */ - {COSTS_N_INSNS (56), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (56), /* HI */ - COSTS_N_INSNS (56), /* SI */ - COSTS_N_INSNS (56), /* DI */ - COSTS_N_INSNS (56)}, /* other */ - COSTS_N_INSNS (1), /* cost of movsx */ - COSTS_N_INSNS (1), /* cost of movzx */ + {56, 56, 56, 56, 56}, /* cost of a divide/mod */ + 1, /* cost of movsx */ + 1, /* cost of movzx */ 16, /* "large" insn */ 6, /* MOVE_RATIO */ 2, /* cost for loading QImode using movzbl */ @@ -521,8 +438,7 @@ struct processor_costs pentium4_cost = { 2, /* cost of reg,reg fld/fst */ {2, 2, 6}, /* cost of loading fp registers in SFmode, DFmode and XFmode */ - {4, 4, 6}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ + {4, 4, 6}, /* cost of loading integer registers */ 2, /* cost of moving MMX register */ {2, 2}, /* cost of loading MMX registers in SImode and DImode */ @@ -537,179 +453,12 @@ struct processor_costs pentium4_cost = { 64, /* size of prefetch block */ 6, /* number of parallel prefetches */ 2, /* Branch cost */ - COSTS_N_INSNS (5), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (7), /* cost of FMUL instruction. */ - COSTS_N_INSNS (43), /* cost of FDIV instruction. */ - COSTS_N_INSNS (2), /* cost of FABS instruction. */ - COSTS_N_INSNS (2), /* cost of FCHS instruction. */ - COSTS_N_INSNS (43), /* cost of FSQRT instruction. */ -}; - -static const -struct processor_costs nocona_cost = { - COSTS_N_INSNS (1), /* cost of an add instruction */ - COSTS_N_INSNS (1), /* cost of a lea instruction */ - COSTS_N_INSNS (1), /* variable shift costs */ - COSTS_N_INSNS (1), /* constant shift costs */ - {COSTS_N_INSNS (10), /* cost of starting multiply for QI */ - COSTS_N_INSNS (10), /* HI */ - COSTS_N_INSNS (10), /* SI */ - COSTS_N_INSNS (10), /* DI */ - COSTS_N_INSNS (10)}, /* other */ - 0, /* cost of multiply per each bit set */ - {COSTS_N_INSNS (66), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (66), /* HI */ - COSTS_N_INSNS (66), /* SI */ - COSTS_N_INSNS (66), /* DI */ - COSTS_N_INSNS (66)}, /* other */ - COSTS_N_INSNS (1), /* cost of movsx */ - COSTS_N_INSNS (1), /* cost of movzx */ - 16, /* "large" insn */ - 17, /* MOVE_RATIO */ - 4, /* cost for loading QImode using movzbl */ - {4, 4, 4}, /* cost of loading integer registers - in QImode, HImode and SImode. - Relative to reg-reg move (2). */ - {4, 4, 4}, /* cost of storing integer registers */ - 3, /* cost of reg,reg fld/fst */ - {12, 12, 12}, /* cost of loading fp registers - in SFmode, DFmode and XFmode */ - {4, 4, 4}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ - 6, /* cost of moving MMX register */ - {12, 12}, /* cost of loading MMX registers - in SImode and DImode */ - {12, 12}, /* cost of storing MMX registers - in SImode and DImode */ - 6, /* cost of moving SSE register */ - {12, 12, 12}, /* cost of loading SSE registers - in SImode, DImode and TImode */ - {12, 12, 12}, /* cost of storing SSE registers - in SImode, DImode and TImode */ - 8, /* MMX or SSE register to integer */ - 128, /* size of prefetch block */ - 8, /* number of parallel prefetches */ - 1, /* Branch cost */ - COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (8), /* cost of FMUL instruction. */ - COSTS_N_INSNS (40), /* cost of FDIV instruction. */ - COSTS_N_INSNS (3), /* cost of FABS instruction. */ - COSTS_N_INSNS (3), /* cost of FCHS instruction. */ - COSTS_N_INSNS (44), /* cost of FSQRT instruction. */ -}; - -/* Generic64 should produce code tuned for Nocona and K8. */ -static const -struct processor_costs generic64_cost = { - COSTS_N_INSNS (1), /* cost of an add instruction */ - /* On all chips taken into consideration lea is 2 cycles and more. With - this cost however our current implementation of synth_mult results in - use of unnecessary temporary registers causing regression on several - SPECfp benchmarks. */ - COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */ - COSTS_N_INSNS (1), /* variable shift costs */ - COSTS_N_INSNS (1), /* constant shift costs */ - {COSTS_N_INSNS (3), /* cost of starting multiply for QI */ - COSTS_N_INSNS (4), /* HI */ - COSTS_N_INSNS (3), /* SI */ - COSTS_N_INSNS (4), /* DI */ - COSTS_N_INSNS (2)}, /* other */ - 0, /* cost of multiply per each bit set */ - {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (26), /* HI */ - COSTS_N_INSNS (42), /* SI */ - COSTS_N_INSNS (74), /* DI */ - COSTS_N_INSNS (74)}, /* other */ - COSTS_N_INSNS (1), /* cost of movsx */ - COSTS_N_INSNS (1), /* cost of movzx */ - 8, /* "large" insn */ - 17, /* MOVE_RATIO */ - 4, /* cost for loading QImode using movzbl */ - {4, 4, 4}, /* cost of loading integer registers - in QImode, HImode and SImode. - Relative to reg-reg move (2). */ - {4, 4, 4}, /* cost of storing integer registers */ - 4, /* cost of reg,reg fld/fst */ - {12, 12, 12}, /* cost of loading fp registers - in SFmode, DFmode and XFmode */ - {6, 6, 8}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ - 2, /* cost of moving MMX register */ - {8, 8}, /* cost of loading MMX registers - in SImode and DImode */ - {8, 8}, /* cost of storing MMX registers - in SImode and DImode */ - 2, /* cost of moving SSE register */ - {8, 8, 8}, /* cost of loading SSE registers - in SImode, DImode and TImode */ - {8, 8, 8}, /* cost of storing SSE registers - in SImode, DImode and TImode */ - 5, /* MMX or SSE register to integer */ - 64, /* size of prefetch block */ - 6, /* number of parallel prefetches */ - /* Benchmarks shows large regressions on K8 sixtrack benchmark when this value - is increased to perhaps more appropriate value of 5. */ - 3, /* Branch cost */ - COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (8), /* cost of FMUL instruction. */ - COSTS_N_INSNS (20), /* cost of FDIV instruction. */ - COSTS_N_INSNS (8), /* cost of FABS instruction. */ - COSTS_N_INSNS (8), /* cost of FCHS instruction. */ - COSTS_N_INSNS (40), /* cost of FSQRT instruction. */ -}; - -/* Generic32 should produce code tuned for Athlon, PPro, Pentium4, Nocona and K8. */ -static const -struct processor_costs generic32_cost = { - COSTS_N_INSNS (1), /* cost of an add instruction */ - COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */ - COSTS_N_INSNS (1), /* variable shift costs */ - COSTS_N_INSNS (1), /* constant shift costs */ - {COSTS_N_INSNS (3), /* cost of starting multiply for QI */ - COSTS_N_INSNS (4), /* HI */ - COSTS_N_INSNS (3), /* SI */ - COSTS_N_INSNS (4), /* DI */ - COSTS_N_INSNS (2)}, /* other */ - 0, /* cost of multiply per each bit set */ - {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */ - COSTS_N_INSNS (26), /* HI */ - COSTS_N_INSNS (42), /* SI */ - COSTS_N_INSNS (74), /* DI */ - COSTS_N_INSNS (74)}, /* other */ - COSTS_N_INSNS (1), /* cost of movsx */ - COSTS_N_INSNS (1), /* cost of movzx */ - 8, /* "large" insn */ - 17, /* MOVE_RATIO */ - 4, /* cost for loading QImode using movzbl */ - {4, 4, 4}, /* cost of loading integer registers - in QImode, HImode and SImode. - Relative to reg-reg move (2). */ - {4, 4, 4}, /* cost of storing integer registers */ - 4, /* cost of reg,reg fld/fst */ - {12, 12, 12}, /* cost of loading fp registers - in SFmode, DFmode and XFmode */ - {6, 6, 8}, /* cost of storing fp registers - in SFmode, DFmode and XFmode */ - 2, /* cost of moving MMX register */ - {8, 8}, /* cost of loading MMX registers - in SImode and DImode */ - {8, 8}, /* cost of storing MMX registers - in SImode and DImode */ - 2, /* cost of moving SSE register */ - {8, 8, 8}, /* cost of loading SSE registers - in SImode, DImode and TImode */ - {8, 8, 8}, /* cost of storing SSE registers - in SImode, DImode and TImode */ - 5, /* MMX or SSE register to integer */ - 64, /* size of prefetch block */ - 6, /* number of parallel prefetches */ - 3, /* Branch cost */ - COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */ - COSTS_N_INSNS (8), /* cost of FMUL instruction. */ - COSTS_N_INSNS (20), /* cost of FDIV instruction. */ - COSTS_N_INSNS (8), /* cost of FABS instruction. */ - COSTS_N_INSNS (8), /* cost of FCHS instruction. */ - COSTS_N_INSNS (40), /* cost of FSQRT instruction. */ + 5, /* cost of FADD and FSUB insns. */ + 7, /* cost of FMUL instruction. */ + 43, /* cost of FDIV instruction. */ + 2, /* cost of FABS instruction. */ + 2, /* cost of FCHS instruction. */ + 43, /* cost of FSQRT instruction. */ }; const struct processor_costs *ix86_cost = &pentium_cost; @@ -724,112 +473,68 @@ const struct processor_costs *ix86_cost = &pentium_cost; #define m_PENT4 (1<<PROCESSOR_PENTIUM4) #define m_K8 (1<<PROCESSOR_K8) #define m_ATHLON_K8 (m_K8 | m_ATHLON) -#define m_NOCONA (1<<PROCESSOR_NOCONA) -#define m_GENERIC32 (1<<PROCESSOR_GENERIC32) -#define m_GENERIC64 (1<<PROCESSOR_GENERIC64) -#define m_GENERIC (m_GENERIC32 | m_GENERIC64) - -/* Generic instruction choice should be common subset of supported CPUs - (PPro/PENT4/NOCONA/Athlon/K8). */ - -/* Leave is not affecting Nocona SPEC2000 results negatively, so enabling for - Generic64 seems like good code size tradeoff. We can't enable it for 32bit - generic because it is not working well with PPro base chips. */ -const int x86_use_leave = m_386 | m_K6 | m_ATHLON_K8 | m_GENERIC64; -const int x86_push_memory = m_386 | m_K6 | m_ATHLON_K8 | m_PENT4 | m_NOCONA | m_GENERIC; + +const int x86_use_leave = m_386 | m_K6 | m_ATHLON_K8; +const int x86_push_memory = m_386 | m_K6 | m_ATHLON_K8 | m_PENT4; const int x86_zero_extend_with_and = m_486 | m_PENT; -const int x86_movx = m_ATHLON_K8 | m_PPRO | m_PENT4 | m_NOCONA | m_GENERIC /* m_386 | m_K6 */; +const int x86_movx = m_ATHLON_K8 | m_PPRO | m_PENT4 /* m_386 | m_K6 */; const int x86_double_with_add = ~m_386; const int x86_use_bit_test = m_386; -const int x86_unroll_strlen = m_486 | m_PENT | m_PPRO | m_ATHLON_K8 | m_K6 | m_GENERIC; -const int x86_cmove = m_PPRO | m_ATHLON_K8 | m_PENT4 | m_NOCONA; +const int x86_unroll_strlen = m_486 | m_PENT | m_PPRO | m_ATHLON_K8 | m_K6; +const int x86_cmove = m_PPRO | m_ATHLON_K8 | m_PENT4; const int x86_3dnow_a = m_ATHLON_K8; -const int x86_deep_branch = m_PPRO | m_K6 | m_ATHLON_K8 | m_PENT4 | m_NOCONA | m_GENERIC; -/* Branch hints were put in P4 based on simulation result. But - after P4 was made, no performance benefit was observed with - branch hints. It also increases the code size. As the result, - icc never generates branch hints. */ -const int x86_branch_hints = 0; -const int x86_use_sahf = m_PPRO | m_K6 | m_PENT4 | m_NOCONA | m_GENERIC32; /*m_GENERIC | m_ATHLON_K8 ? */ -/* We probably ought to watch for partial register stalls on Generic32 - compilation setting as well. However in current implementation the - partial register stalls are not eliminated very well - they can - be introduced via subregs synthesized by combine and can happen - in caller/callee saving sequences. - Because this option pays back little on PPro based chips and is in conflict - with partial reg. dependencies used by Athlon/P4 based chips, it is better - to leave it off for generic32 for now. */ +const int x86_deep_branch = m_PPRO | m_K6 | m_ATHLON_K8 | m_PENT4; +const int x86_branch_hints = m_PENT4; +const int x86_use_sahf = m_PPRO | m_K6 | m_PENT4; const int x86_partial_reg_stall = m_PPRO; -const int x86_partial_flag_reg_stall = m_GENERIC; -const int x86_use_himode_fiop = m_386 | m_486 | m_K6; -const int x86_use_simode_fiop = ~(m_PPRO | m_ATHLON_K8 | m_PENT | m_GENERIC); +const int x86_use_loop = m_K6; +const int x86_use_fiop = ~(m_PPRO | m_ATHLON_K8 | m_PENT); const int x86_use_mov0 = m_K6; -const int x86_use_cltd = ~(m_PENT | m_K6 | m_GENERIC); +const int x86_use_cltd = ~(m_PENT | m_K6); const int x86_read_modify_write = ~m_PENT; const int x86_read_modify = ~(m_PENT | m_PPRO); const int x86_split_long_moves = m_PPRO; -const int x86_promote_QImode = m_K6 | m_PENT | m_386 | m_486 | m_ATHLON_K8 | m_GENERIC; /* m_PENT4 ? */ +const int x86_promote_QImode = m_K6 | m_PENT | m_386 | m_486 | m_ATHLON_K8; const int x86_fast_prefix = ~(m_PENT | m_486 | m_386); -const int x86_single_stringop = m_386 | m_PENT4 | m_NOCONA; +const int x86_single_stringop = m_386 | m_PENT4; const int x86_qimode_math = ~(0); const int x86_promote_qi_regs = 0; -/* On PPro this flag is meant to avoid partial register stalls. Just like - the x86_partial_reg_stall this option might be considered for Generic32 - if our scheme for avoiding partial stalls was more effective. */ const int x86_himode_math = ~(m_PPRO); const int x86_promote_hi_regs = m_PPRO; -const int x86_sub_esp_4 = m_ATHLON_K8 | m_PPRO | m_PENT4 | m_NOCONA | m_GENERIC; -const int x86_sub_esp_8 = m_ATHLON_K8 | m_PPRO | m_386 | m_486 | m_PENT4 | m_NOCONA | m_GENERIC; -const int x86_add_esp_4 = m_ATHLON_K8 | m_K6 | m_PENT4 | m_NOCONA | m_GENERIC; -const int x86_add_esp_8 = m_ATHLON_K8 | m_PPRO | m_K6 | m_386 | m_486 | m_PENT4 | m_NOCONA | m_GENERIC; -const int x86_integer_DFmode_moves = ~(m_ATHLON_K8 | m_PENT4 | m_NOCONA | m_PPRO | m_GENERIC); -const int x86_partial_reg_dependency = m_ATHLON_K8 | m_PENT4 | m_NOCONA | m_GENERIC; -const int x86_memory_mismatch_stall = m_ATHLON_K8 | m_PENT4 | m_NOCONA | m_GENERIC; -const int x86_accumulate_outgoing_args = m_ATHLON_K8 | m_PENT4 | m_NOCONA | m_PPRO | m_GENERIC; -const int x86_prologue_using_move = m_ATHLON_K8 | m_PPRO | m_GENERIC; -const int x86_epilogue_using_move = m_ATHLON_K8 | m_PPRO | m_GENERIC; +const int x86_sub_esp_4 = m_ATHLON_K8 | m_PPRO | m_PENT4; +const int x86_sub_esp_8 = m_ATHLON_K8 | m_PPRO | m_386 | m_486 | m_PENT4; +const int x86_add_esp_4 = m_ATHLON_K8 | m_K6 | m_PENT4; +const int x86_add_esp_8 = m_ATHLON_K8 | m_PPRO | m_K6 | m_386 | m_486 | m_PENT4; +const int x86_integer_DFmode_moves = ~(m_ATHLON_K8 | m_PENT4 | m_PPRO); +const int x86_partial_reg_dependency = m_ATHLON_K8 | m_PENT4; +const int x86_memory_mismatch_stall = m_ATHLON_K8 | m_PENT4; +const int x86_accumulate_outgoing_args = m_ATHLON_K8 | m_PENT4 | m_PPRO; +const int x86_prologue_using_move = m_ATHLON_K8 | m_PENT4 | m_PPRO; +const int x86_epilogue_using_move = m_ATHLON_K8 | m_PENT4 | m_PPRO; +const int x86_decompose_lea = m_PENT4; const int x86_shift1 = ~m_486; -const int x86_arch_always_fancy_math_387 = m_PENT | m_PPRO | m_ATHLON_K8 | m_PENT4 | m_NOCONA | m_GENERIC; -/* In Generic model we have an conflict here in between PPro/Pentium4 based chips - that thread 128bit SSE registers as single units versus K8 based chips that - divide SSE registers to two 64bit halves. - x86_sse_partial_reg_dependency promote all store destinations to be 128bit - to allow register renaming on 128bit SSE units, but usually results in one - extra microop on 64bit SSE units. Experimental results shows that disabling - this option on P4 brings over 20% SPECfp regression, while enabling it on - K8 brings roughly 2.4% regression that can be partly masked by careful scheduling - of moves. */ -const int x86_sse_partial_reg_dependency = m_PENT4 | m_NOCONA | m_PPRO | m_GENERIC; -/* Set for machines where the type and dependencies are resolved on SSE - register parts instead of whole registers, so we may maintain just - lower part of scalar values in proper format leaving the upper part - undefined. */ -const int x86_sse_split_regs = m_ATHLON_K8; +const int x86_arch_always_fancy_math_387 = m_PENT | m_PPRO | m_ATHLON_K8 | m_PENT4; +const int x86_sse_partial_reg_dependency = m_PENT4 | m_PPRO; +/* Set for machines where the type and dependencies are resolved on SSE register + parts instead of whole registers, so we may maintain just lower part of + scalar values in proper format leaving the upper part undefined. */ +const int x86_sse_partial_regs = m_ATHLON_K8; +/* Athlon optimizes partial-register FPS special case, thus avoiding the + need for extra instructions beforehand */ +const int x86_sse_partial_regs_for_cvtsd2ss = 0; const int x86_sse_typeless_stores = m_ATHLON_K8; -const int x86_sse_load0_by_pxor = m_PPRO | m_PENT4 | m_NOCONA; +const int x86_sse_load0_by_pxor = m_PPRO | m_PENT4; const int x86_use_ffreep = m_ATHLON_K8; const int x86_rep_movl_optimal = m_386 | m_PENT | m_PPRO | m_K6; -const int x86_use_incdec = ~(m_PENT4 | m_NOCONA | m_GENERIC); - -/* ??? Allowing interunit moves makes it all too easy for the compiler to put - integer data in xmm registers. Which results in pretty abysmal code. */ -const int x86_inter_unit_moves = 0 /* ~(m_ATHLON_K8) */; - -const int x86_ext_80387_constants = m_K6 | m_ATHLON | m_PENT4 | m_NOCONA | m_PPRO | m_GENERIC32; -/* Some CPU cores are not able to predict more than 4 branch instructions in - the 16 byte window. */ -const int x86_four_jump_limit = m_PPRO | m_ATHLON_K8 | m_PENT4 | m_NOCONA | m_GENERIC; -const int x86_schedule = m_PPRO | m_ATHLON_K8 | m_K6 | m_PENT | m_GENERIC; -const int x86_use_bt = m_ATHLON_K8; -/* Compare and exchange was added for 80486. */ -const int x86_cmpxchg = ~m_386; -/* Compare and exchange 8 bytes was added for pentium. */ -const int x86_cmpxchg8b = ~(m_386 | m_486); -/* Compare and exchange 16 bytes was added for nocona. */ -const int x86_cmpxchg16b = m_NOCONA; -/* Exchange and add was added for 80486. */ -const int x86_xadd = ~m_386; -const int x86_pad_returns = m_ATHLON_K8 | m_GENERIC; + +/* ??? HACK! The following is a lie. SSE can hold e.g. SImode, and + indeed *must* be able to hold SImode so that SSE2 shifts are able + to work right. But this can result in some mighty surprising + register allocation when building kernels. Turning this off should + make us less likely to all-of-the-sudden select an SSE register. */ +const int x86_inter_unit_moves = 0; /* ~(m_ATHLON_K8) */ + +const int x86_ext_80387_constants = m_K6 | m_ATHLON | m_PENT4 | m_PPRO; /* In case the average insn count for single function invocation is lower than this constant, emit fast (but longer) prologue and @@ -973,8 +678,8 @@ int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER] = rtx ix86_compare_op0 = NULL_RTX; rtx ix86_compare_op1 = NULL_RTX; -rtx ix86_compare_emitted = NULL_RTX; +#define MAX_386_STACK_LOCALS 3 /* Size of the register save area. */ #define X86_64_VARARGS_SIZE (REGPARM_MAX * UNITS_PER_WORD + SSE_REGPARM_MAX * 16) @@ -1028,11 +733,17 @@ struct ix86_frame bool save_regs_using_mov; }; -/* Code model option. */ +/* Used to enable/disable debugging features. */ +const char *ix86_debug_arg_string, *ix86_debug_addr_string; +/* Code model option as passed by user. */ +const char *ix86_cmodel_string; +/* Parsed value. */ enum cmodel ix86_cmodel; /* Asm dialect. */ +const char *ix86_asm_string; enum asm_dialect ix86_asm_dialect = ASM_ATT; -/* TLS dialects. */ +/* TLS dialext. */ +const char *ix86_tls_dialect_string; enum tls_dialect ix86_tls_dialect = TLS_DIALECT_GNU; /* Which unit we are generating floating point math for. */ @@ -1043,37 +754,53 @@ enum processor_type ix86_tune; /* Which instruction set architecture to use. */ enum processor_type ix86_arch; +/* Strings to hold which cpu and instruction set architecture to use. */ +const char *ix86_tune_string; /* for -mtune=<xxx> */ +const char *ix86_arch_string; /* for -march=<xxx> */ +const char *ix86_fpmath_string; /* for -mfpmath=<xxx> */ + +/* # of registers to use to pass arguments. */ +const char *ix86_regparm_string; + /* true if sse prefetch instruction is not NOOP. */ int x86_prefetch_sse; /* ix86_regparm_string as a number */ -static int ix86_regparm; +int ix86_regparm; -/* -mstackrealign option */ -extern int ix86_force_align_arg_pointer; -static const char ix86_force_align_arg_pointer_string[] = "force_align_arg_pointer"; +/* Alignment to use for loops and jumps: */ + +/* Power of two alignment for loops. */ +const char *ix86_align_loops_string; + +/* Power of two alignment for non-loop jumps. */ +const char *ix86_align_jumps_string; + +/* Power of two alignment for stack boundary in bytes. */ +const char *ix86_preferred_stack_boundary_string; /* Preferred alignment for stack boundary in bits. */ -unsigned int ix86_preferred_stack_boundary; +int ix86_preferred_stack_boundary; /* Values 1-5: see jump.c */ int ix86_branch_cost; +const char *ix86_branch_cost_string; -/* Variables which are this size or smaller are put in the data/bss - or ldata/lbss sections. */ - -int ix86_section_threshold = 65536; +/* Power of two alignment for functions. */ +const char *ix86_align_funcs_string; /* Prefix built by ASM_GENERATE_INTERNAL_LABEL. */ -char internal_label_prefix[16]; -int internal_label_prefix_len; +static char internal_label_prefix[16]; +static int internal_label_prefix_len; -static bool ix86_handle_option (size_t, const char *, int); +static int local_symbolic_operand (rtx, enum machine_mode); +static int tls_symbolic_operand_1 (rtx, enum tls_model); static void output_pic_addr_const (FILE *, rtx, int); static void put_condition_code (enum rtx_code, enum machine_mode, int, int, FILE *); static const char *get_some_local_dynamic_name (void); static int get_some_local_dynamic_name_1 (rtx *, void *); +static rtx maybe_get_pool_constant (rtx); static rtx ix86_expand_int_compare (enum rtx_code, rtx, rtx); static enum rtx_code ix86_prepare_fp_compare_args (enum rtx_code, rtx *, rtx *); @@ -1084,8 +811,12 @@ static rtx get_thread_pointer (int); static rtx legitimize_tls_address (rtx, enum tls_model, int); static void get_pc_thunk_name (char [32], unsigned int); static rtx gen_push (rtx); -static int ix86_flags_dependent (rtx, rtx, enum attr_type); -static int ix86_agi_dependent (rtx, rtx, enum attr_type); +static int memory_address_length (rtx addr); +static int ix86_flags_dependant (rtx, rtx, enum attr_type); +static int ix86_agi_dependant (rtx, rtx, enum attr_type); +static enum attr_ppro_uops ix86_safe_ppro_uops (rtx); +static void ix86_dump_ppro_packet (FILE *); +static void ix86_reorder_insn (rtx *, rtx *); static struct machine_function * ix86_init_machine_status (void); static int ix86_split_to_parts (rtx, rtx *, enum machine_mode); static int ix86_nsaved_regs (void); @@ -1093,12 +824,17 @@ static void ix86_emit_save_regs (void); static void ix86_emit_save_regs_using_mov (rtx, HOST_WIDE_INT); static void ix86_emit_restore_regs_using_mov (rtx, HOST_WIDE_INT, int); static void ix86_output_function_epilogue (FILE *, HOST_WIDE_INT); +static void ix86_sched_reorder_ppro (rtx *, rtx *); static HOST_WIDE_INT ix86_GOT_alias_set (void); static void ix86_adjust_counter (rtx, HOST_WIDE_INT); static rtx ix86_expand_aligntest (rtx, int); static void ix86_expand_strlensi_unroll_1 (rtx, rtx, rtx); static int ix86_issue_rate (void); static int ix86_adjust_cost (rtx, rtx, rtx, int); +static void ix86_sched_init (FILE *, int, int); +static int ix86_sched_reorder (FILE *, int, rtx *, int *, int); +static int ix86_variable_issue (FILE *, int, rtx, int); +static int ia32_use_dfa_pipeline_interface (void); static int ia32_multipass_dfa_lookahead (void); static void ix86_init_mmx_sse_builtins (void); static rtx x86_this_parameter (tree); @@ -1109,18 +845,19 @@ static void x86_file_start (void); static void ix86_reorg (void); static bool ix86_expand_carry_flag_compare (enum rtx_code, rtx, rtx, rtx*); static tree ix86_build_builtin_va_list (void); -static void ix86_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, - tree, int *, int); -static tree ix86_gimplify_va_arg (tree, tree, tree *, tree *); -static bool ix86_scalar_mode_supported_p (enum machine_mode); -static bool ix86_vector_mode_supported_p (enum machine_mode); +struct ix86_address +{ + rtx base, index, disp; + HOST_WIDE_INT scale; + enum ix86_address_seg { SEG_DEFAULT, SEG_FS, SEG_GS } seg; +}; + +static int ix86_decompose_address (rtx, struct ix86_address *); static int ix86_address_cost (rtx); static bool ix86_cannot_force_const_mem (rtx); static rtx ix86_delegitimize_address (rtx); -static void i386_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED; - struct builtin_description; static rtx ix86_expand_sse_comi (const struct builtin_description *, tree, rtx); @@ -1131,6 +868,9 @@ static rtx ix86_expand_unop_builtin (enum insn_code, tree, rtx, int); static rtx ix86_expand_binop_builtin (enum insn_code, tree, rtx); static rtx ix86_expand_store_builtin (enum insn_code, tree); static rtx safe_vector_operand (rtx, enum machine_mode); +static enum rtx_code ix86_fp_compare_code_to_integer (enum rtx_code); +static void ix86_fp_comparison_codes (enum rtx_code code, enum rtx_code *, + enum rtx_code *, enum rtx_code *); static rtx ix86_expand_fp_compare (enum rtx_code, rtx, rtx, rtx, rtx *, rtx *); static int ix86_fp_comparison_arithmetics_cost (enum rtx_code code); static int ix86_fp_comparison_fcomi_cost (enum rtx_code code); @@ -1143,29 +883,20 @@ static int ix86_comp_type_attributes (tree, tree); static int ix86_function_regparm (tree, tree); const struct attribute_spec ix86_attribute_table[]; static bool ix86_function_ok_for_sibcall (tree, tree); -static tree ix86_handle_cconv_attribute (tree *, tree, tree, int, bool *); -static int ix86_value_regno (enum machine_mode, tree, tree); +static tree ix86_handle_cdecl_attribute (tree *, tree, tree, int, bool *); +static tree ix86_handle_regparm_attribute (tree *, tree, tree, int, bool *); +static int ix86_value_regno (enum machine_mode); static bool contains_128bit_aligned_vector_p (tree); -static rtx ix86_struct_value_rtx (tree, int); static bool ix86_ms_bitfield_layout_p (tree); static tree ix86_handle_struct_attribute (tree *, tree, tree, int, bool *); static int extended_reg_mentioned_1 (rtx *, void *); static bool ix86_rtx_costs (rtx, int, int, int *); static int min_insn_size (rtx); -static tree ix86_md_asm_clobbers (tree outputs, tree inputs, tree clobbers); -static bool ix86_must_pass_in_stack (enum machine_mode mode, tree type); -static bool ix86_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, - tree, bool); -static void ix86_init_builtins (void); -static rtx ix86_expand_builtin (tree, rtx, rtx, enum machine_mode, int); -static const char *ix86_mangle_fundamental_type (tree); -static tree ix86_stack_protect_fail (void); -static rtx ix86_internal_arg_pointer (void); -static void ix86_dwarf_handle_frame_unspec (const char *, rtx, int); - -/* This function is only used on Solaris. */ -static void i386_solaris_elf_named_section (const char *, unsigned int, tree) - ATTRIBUTE_UNUSED; +static void k8_avoid_jump_misspredicts (void); + +#if defined (DO_GLOBAL_CTORS_BODY) && defined (HAS_INIT_SECTION) +static void ix86_svr3_asm_out_constructor (rtx, int); +#endif /* Register class used for passing given 64bit part of the argument. These represent classes as documented by the PS ABI, with the exception @@ -1186,31 +917,29 @@ enum x86_64_reg_class X86_64_SSEUP_CLASS, X86_64_X87_CLASS, X86_64_X87UP_CLASS, - X86_64_COMPLEX_X87_CLASS, X86_64_MEMORY_CLASS }; -static const char * const x86_64_reg_class_name[] = { - "no", "integer", "integerSI", "sse", "sseSF", "sseDF", - "sseup", "x87", "x87up", "cplx87", "no" -}; +static const char * const x86_64_reg_class_name[] = + {"no", "integer", "integerSI", "sse", "sseSF", "sseDF", "sseup", "x87", "x87up", "no"}; #define MAX_CLASSES 4 +static int classify_argument (enum machine_mode, tree, + enum x86_64_reg_class [MAX_CLASSES], int); +static int examine_argument (enum machine_mode, tree, int, int *, int *); +static rtx construct_container (enum machine_mode, tree, int, int, int, + const int *, int); +static enum x86_64_reg_class merge_classes (enum x86_64_reg_class, + enum x86_64_reg_class); /* Table of constants used by fldpi, fldln2, etc.... */ static REAL_VALUE_TYPE ext_80387_constants_table [5]; static bool ext_80387_constants_init = 0; static void init_ext_80387_constants (void); -static bool ix86_in_large_data_p (tree) ATTRIBUTE_UNUSED; -static void ix86_encode_section_info (tree, rtx, int) ATTRIBUTE_UNUSED; -static void x86_64_elf_unique_section (tree decl, int reloc) ATTRIBUTE_UNUSED; -static section *x86_64_elf_select_section (tree decl, int reloc, - unsigned HOST_WIDE_INT align) - ATTRIBUTE_UNUSED; /* Initialize the GCC target structure. */ #undef TARGET_ATTRIBUTE_TABLE #define TARGET_ATTRIBUTE_TABLE ix86_attribute_table -#if TARGET_DLLIMPORT_DECL_ATTRIBUTES +#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES # undef TARGET_MERGE_DECL_ATTRIBUTES # define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes #endif @@ -1220,19 +949,13 @@ static section *x86_64_elf_select_section (tree decl, int reloc, #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS ix86_init_builtins + #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN ix86_expand_builtin #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE ix86_output_function_epilogue -#undef TARGET_ENCODE_SECTION_INFO -#ifndef SUBTARGET_ENCODE_SECTION_INFO -#define TARGET_ENCODE_SECTION_INFO ix86_encode_section_info -#else -#define TARGET_ENCODE_SECTION_INFO SUBTARGET_ENCODE_SECTION_INFO -#endif - #undef TARGET_ASM_OPEN_PAREN #define TARGET_ASM_OPEN_PAREN "" #undef TARGET_ASM_CLOSE_PAREN @@ -1258,6 +981,15 @@ static section *x86_64_elf_select_section (tree decl, int reloc, #define TARGET_SCHED_ADJUST_COST ix86_adjust_cost #undef TARGET_SCHED_ISSUE_RATE #define TARGET_SCHED_ISSUE_RATE ix86_issue_rate +#undef TARGET_SCHED_VARIABLE_ISSUE +#define TARGET_SCHED_VARIABLE_ISSUE ix86_variable_issue +#undef TARGET_SCHED_INIT +#define TARGET_SCHED_INIT ix86_sched_init +#undef TARGET_SCHED_REORDER +#define TARGET_SCHED_REORDER ix86_sched_reorder +#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE +#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \ + ia32_use_dfa_pipeline_interface #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \ ia32_multipass_dfa_lookahead @@ -1271,8 +1003,6 @@ static section *x86_64_elf_select_section (tree decl, int reloc, #endif #undef TARGET_CANNOT_FORCE_CONST_MEM #define TARGET_CANNOT_FORCE_CONST_MEM ix86_cannot_force_const_mem -#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P -#define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_rtx_true #undef TARGET_DELEGITIMIZE_ADDRESS #define TARGET_DELEGITIMIZE_ADDRESS ix86_delegitimize_address @@ -1280,11 +1010,6 @@ static section *x86_64_elf_select_section (tree decl, int reloc, #undef TARGET_MS_BITFIELD_LAYOUT_P #define TARGET_MS_BITFIELD_LAYOUT_P ix86_ms_bitfield_layout_p -#if TARGET_MACHO -#undef TARGET_BINDS_LOCAL_P -#define TARGET_BINDS_LOCAL_P darwin_binds_local_p -#endif - #undef TARGET_ASM_OUTPUT_MI_THUNK #define TARGET_ASM_OUTPUT_MI_THUNK x86_output_mi_thunk #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK @@ -1293,16 +1018,6 @@ static section *x86_64_elf_select_section (tree decl, int reloc, #undef TARGET_ASM_FILE_START #define TARGET_ASM_FILE_START x86_file_start -#undef TARGET_DEFAULT_TARGET_FLAGS -#define TARGET_DEFAULT_TARGET_FLAGS \ - (TARGET_DEFAULT \ - | TARGET_64BIT_DEFAULT \ - | TARGET_SUBTARGET_DEFAULT \ - | TARGET_TLS_DIRECT_SEG_REFS_DEFAULT) - -#undef TARGET_HANDLE_OPTION -#define TARGET_HANDLE_OPTION ix86_handle_option - #undef TARGET_RTX_COSTS #define TARGET_RTX_COSTS ix86_rtx_costs #undef TARGET_ADDRESS_COST @@ -1319,54 +1034,7 @@ static section *x86_64_elf_select_section (tree decl, int reloc, #undef TARGET_BUILD_BUILTIN_VA_LIST #define TARGET_BUILD_BUILTIN_VA_LIST ix86_build_builtin_va_list -#undef TARGET_MD_ASM_CLOBBERS -#define TARGET_MD_ASM_CLOBBERS ix86_md_asm_clobbers - -#undef TARGET_PROMOTE_PROTOTYPES -#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true -#undef TARGET_STRUCT_VALUE_RTX -#define TARGET_STRUCT_VALUE_RTX ix86_struct_value_rtx -#undef TARGET_SETUP_INCOMING_VARARGS -#define TARGET_SETUP_INCOMING_VARARGS ix86_setup_incoming_varargs -#undef TARGET_MUST_PASS_IN_STACK -#define TARGET_MUST_PASS_IN_STACK ix86_must_pass_in_stack -#undef TARGET_PASS_BY_REFERENCE -#define TARGET_PASS_BY_REFERENCE ix86_pass_by_reference -#undef TARGET_INTERNAL_ARG_POINTER -#define TARGET_INTERNAL_ARG_POINTER ix86_internal_arg_pointer -#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC -#define TARGET_DWARF_HANDLE_FRAME_UNSPEC ix86_dwarf_handle_frame_unspec - -#undef TARGET_GIMPLIFY_VA_ARG_EXPR -#define TARGET_GIMPLIFY_VA_ARG_EXPR ix86_gimplify_va_arg - -#undef TARGET_SCALAR_MODE_SUPPORTED_P -#define TARGET_SCALAR_MODE_SUPPORTED_P ix86_scalar_mode_supported_p - -#undef TARGET_VECTOR_MODE_SUPPORTED_P -#define TARGET_VECTOR_MODE_SUPPORTED_P ix86_vector_mode_supported_p - -#ifdef HAVE_AS_TLS -#undef TARGET_ASM_OUTPUT_DWARF_DTPREL -#define TARGET_ASM_OUTPUT_DWARF_DTPREL i386_output_dwarf_dtprel -#endif - -#ifdef SUBTARGET_INSERT_ATTRIBUTES -#undef TARGET_INSERT_ATTRIBUTES -#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES -#endif - -#undef TARGET_MANGLE_FUNDAMENTAL_TYPE -#define TARGET_MANGLE_FUNDAMENTAL_TYPE ix86_mangle_fundamental_type - -#undef TARGET_STACK_PROTECT_FAIL -#define TARGET_STACK_PROTECT_FAIL ix86_stack_protect_fail - -#undef TARGET_FUNCTION_VALUE -#define TARGET_FUNCTION_VALUE ix86_function_value - struct gcc_target targetm = TARGET_INITIALIZER; - /* The svr4 ABI for the i386 says that records and unions are returned in memory. */ @@ -1374,50 +1042,6 @@ struct gcc_target targetm = TARGET_INITIALIZER; #define DEFAULT_PCC_STRUCT_RETURN 1 #endif -/* Implement TARGET_HANDLE_OPTION. */ - -static bool -ix86_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, int value) -{ - switch (code) - { - case OPT_m3dnow: - if (!value) - { - target_flags &= ~MASK_3DNOW_A; - target_flags_explicit |= MASK_3DNOW_A; - } - return true; - - case OPT_mmmx: - if (!value) - { - target_flags &= ~(MASK_3DNOW | MASK_3DNOW_A); - target_flags_explicit |= MASK_3DNOW | MASK_3DNOW_A; - } - return true; - - case OPT_msse: - if (!value) - { - target_flags &= ~(MASK_SSE2 | MASK_SSE3); - target_flags_explicit |= MASK_SSE2 | MASK_SSE3; - } - return true; - - case OPT_msse2: - if (!value) - { - target_flags &= ~MASK_SSE3; - target_flags_explicit |= MASK_SSE3; - } - return true; - - default: - return true; - } -} - /* Sometimes certain combinations of command options do not make sense on a particular target machine. You can define a macro `OVERRIDE_OPTIONS' to take account of this. This macro, if @@ -1431,8 +1055,6 @@ void override_options (void) { int i; - int ix86_tune_defaulted = 0; - /* Comes from final.c -- no real reason to change it. */ #define MAX_CODE_ALIGN 16 @@ -1456,10 +1078,7 @@ override_options (void) {&k6_cost, 0, 0, 32, 7, 32, 7, 32}, {&athlon_cost, 0, 0, 16, 7, 16, 7, 16}, {&pentium4_cost, 0, 0, 0, 0, 0, 0, 0}, - {&k8_cost, 0, 0, 16, 7, 16, 7, 16}, - {&nocona_cost, 0, 0, 0, 0, 0, 0, 0}, - {&generic32_cost, 0, 0, 16, 7, 16, 7, 16}, - {&generic64_cost, 0, 0, 16, 7, 16, 7, 16} + {&k8_cost, 0, 0, 16, 7, 16, 7, 16} }; static const char * const cpu_names[] = TARGET_CPU_DEFAULT_NAMES; @@ -1500,10 +1119,10 @@ override_options (void) | PTA_MMX | PTA_PREFETCH_SSE}, {"pentium4m", PROCESSOR_PENTIUM4, PTA_SSE | PTA_SSE2 | PTA_MMX | PTA_PREFETCH_SSE}, - {"prescott", PROCESSOR_NOCONA, PTA_SSE | PTA_SSE2 | PTA_SSE3 - | PTA_MMX | PTA_PREFETCH_SSE}, - {"nocona", PROCESSOR_NOCONA, PTA_SSE | PTA_SSE2 | PTA_SSE3 | PTA_64BIT + {"prescott", PROCESSOR_PENTIUM4, PTA_SSE | PTA_SSE2 | PTA_SSE3 | PTA_MMX | PTA_PREFETCH_SSE}, + {"nocona", PROCESSOR_PENTIUM4, PTA_SSE | PTA_SSE2 | PTA_SSE3 | PTA_64BIT + | PTA_MMX | PTA_PREFETCH_SSE}, {"k6", PROCESSOR_K6, PTA_MMX}, {"k6-2", PROCESSOR_K6, PTA_MMX | PTA_3DNOW}, {"k6-3", PROCESSOR_K6, PTA_MMX | PTA_3DNOW}, @@ -1527,31 +1146,16 @@ override_options (void) | PTA_3DNOW_A | PTA_SSE | PTA_SSE2}, {"athlon-fx", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT | PTA_3DNOW_A | PTA_SSE | PTA_SSE2}, - {"generic32", PROCESSOR_GENERIC32, 0 /* flags are only used for -march switch. */ }, - {"generic64", PROCESSOR_GENERIC64, PTA_64BIT /* flags are only used for -march switch. */ }, }; int const pta_size = ARRAY_SIZE (processor_alias_table); -#ifdef SUBTARGET_OVERRIDE_OPTIONS - SUBTARGET_OVERRIDE_OPTIONS; -#endif - -#ifdef SUBSUBTARGET_OVERRIDE_OPTIONS - SUBSUBTARGET_OVERRIDE_OPTIONS; -#endif - - /* -fPIC is the default for x86_64. */ - if (TARGET_MACHO && TARGET_64BIT) - flag_pic = 2; - /* Set the default values for switches whose default depends on TARGET_64BIT in case they weren't overwritten by command line options. */ if (TARGET_64BIT) { - /* Mach-O doesn't support omitting the frame pointer for now. */ if (flag_omit_frame_pointer == 2) - flag_omit_frame_pointer = (TARGET_MACHO ? 0 : 1); + flag_omit_frame_pointer = 1; if (flag_asynchronous_unwind_tables == 2) flag_asynchronous_unwind_tables = 1; if (flag_pcc_struct_return == 2) @@ -1567,69 +1171,29 @@ override_options (void) flag_pcc_struct_return = DEFAULT_PCC_STRUCT_RETURN; } - /* Need to check -mtune=generic first. */ - if (ix86_tune_string) - { - if (!strcmp (ix86_tune_string, "generic") - || !strcmp (ix86_tune_string, "i686") - /* As special support for cross compilers we read -mtune=native - as -mtune=generic. With native compilers we won't see the - -mtune=native, as it was changed by the driver. */ - || !strcmp (ix86_tune_string, "native")) - { - if (TARGET_64BIT) - ix86_tune_string = "generic64"; - else - ix86_tune_string = "generic32"; - } - else if (!strncmp (ix86_tune_string, "generic", 7)) - error ("bad value (%s) for -mtune= switch", ix86_tune_string); - } - else - { - if (ix86_arch_string) - ix86_tune_string = ix86_arch_string; - if (!ix86_tune_string) - { - ix86_tune_string = cpu_names [TARGET_CPU_DEFAULT]; - ix86_tune_defaulted = 1; - } - - /* ix86_tune_string is set to ix86_arch_string or defaulted. We - need to use a sensible tune option. */ - if (!strcmp (ix86_tune_string, "generic") - || !strcmp (ix86_tune_string, "x86-64") - || !strcmp (ix86_tune_string, "i686")) - { - if (TARGET_64BIT) - ix86_tune_string = "generic64"; - else - ix86_tune_string = "generic32"; - } - } - if (!strcmp (ix86_tune_string, "x86-64")) - warning (OPT_Wdeprecated, "-mtune=x86-64 is deprecated. Use -mtune=k8 or " - "-mtune=generic instead as appropriate."); +#ifdef SUBTARGET_OVERRIDE_OPTIONS + SUBTARGET_OVERRIDE_OPTIONS; +#endif + if (!ix86_tune_string && ix86_arch_string) + ix86_tune_string = ix86_arch_string; + if (!ix86_tune_string) + ix86_tune_string = cpu_names [TARGET_CPU_DEFAULT]; if (!ix86_arch_string) ix86_arch_string = TARGET_64BIT ? "x86-64" : "i386"; - if (!strcmp (ix86_arch_string, "generic")) - error ("generic CPU can be used only for -mtune= switch"); - if (!strncmp (ix86_arch_string, "generic", 7)) - error ("bad value (%s) for -march= switch", ix86_arch_string); if (ix86_cmodel_string != 0) { if (!strcmp (ix86_cmodel_string, "small")) ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL; - else if (!strcmp (ix86_cmodel_string, "medium")) - ix86_cmodel = flag_pic ? CM_MEDIUM_PIC : CM_MEDIUM; else if (flag_pic) sorry ("code model %s not supported in PIC mode", ix86_cmodel_string); else if (!strcmp (ix86_cmodel_string, "32")) ix86_cmodel = CM_32; else if (!strcmp (ix86_cmodel_string, "kernel") && !flag_pic) ix86_cmodel = CM_KERNEL; + else if (!strcmp (ix86_cmodel_string, "medium") && !flag_pic) + ix86_cmodel = CM_MEDIUM; else if (!strcmp (ix86_cmodel_string, "large") && !flag_pic) ix86_cmodel = CM_LARGE; else @@ -1643,8 +1207,7 @@ override_options (void) } if (ix86_asm_string != 0) { - if (! TARGET_MACHO - && !strcmp (ix86_asm_string, "intel")) + if (!strcmp (ix86_asm_string, "intel")) ix86_asm_dialect = ASM_INTEL; else if (!strcmp (ix86_asm_string, "att")) ix86_asm_dialect = ASM_ATT; @@ -1652,10 +1215,10 @@ override_options (void) error ("bad value (%s) for -masm= switch", ix86_asm_string); } if ((TARGET_64BIT == 0) != (ix86_cmodel == CM_32)) - error ("code model %qs not supported in the %s bit mode", + error ("code model `%s' not supported in the %s bit mode", ix86_cmodel_string, TARGET_64BIT ? "64" : "32"); if (ix86_cmodel == CM_LARGE) - sorry ("code model %<large%> not supported yet"); + sorry ("code model `large' not supported yet"); if ((TARGET_64BIT != 0) != ((target_flags & MASK_64BIT) != 0)) sorry ("%i-bit mode not compiled in", (target_flags & MASK_64BIT) ? 64 : 32); @@ -1687,8 +1250,7 @@ override_options (void) if (processor_alias_table[i].flags & PTA_PREFETCH_SSE) x86_prefetch_sse = true; if (TARGET_64BIT && !(processor_alias_table[i].flags & PTA_64BIT)) - error ("CPU you selected does not support x86-64 " - "instruction set"); + error ("CPU you selected does not support x86-64 instruction set"); break; } @@ -1700,21 +1262,9 @@ override_options (void) { ix86_tune = processor_alias_table[i].processor; if (TARGET_64BIT && !(processor_alias_table[i].flags & PTA_64BIT)) - { - if (ix86_tune_defaulted) - { - ix86_tune_string = "x86-64"; - for (i = 0; i < pta_size; i++) - if (! strcmp (ix86_tune_string, - processor_alias_table[i].name)) - break; - ix86_tune = processor_alias_table[i].processor; - } - else - error ("CPU you selected does not support x86-64 " - "instruction set"); - } - /* Intel CPUs have always interpreted SSE prefetch instructions as + error ("CPU you selected does not support x86-64 instruction set"); + + /* Intel CPUs have always interpreted SSE prefetch instructions as NOPs; so, we can enable SSE prefetch instructions even when -mtune (rather than -march) points us to a processor that has them. However, the VIA C3 gives a SIGILL, so we only do that for i686 and @@ -1754,7 +1304,7 @@ override_options (void) Remove this code in GCC 3.2 or later. */ if (ix86_align_loops_string) { - warning (0, "-malign-loops is obsolete, use -falign-loops"); + warning ("-malign-loops is obsolete, use -falign-loops"); if (align_loops == 0) { i = atoi (ix86_align_loops_string); @@ -1767,7 +1317,7 @@ override_options (void) if (ix86_align_jumps_string) { - warning (0, "-malign-jumps is obsolete, use -falign-jumps"); + warning ("-malign-jumps is obsolete, use -falign-jumps"); if (align_jumps == 0) { i = atoi (ix86_align_jumps_string); @@ -1780,7 +1330,7 @@ override_options (void) if (ix86_align_funcs_string) { - warning (0, "-malign-functions is obsolete, use -falign-functions"); + warning ("-malign-functions is obsolete, use -falign-functions"); if (align_functions == 0) { i = atoi (ix86_align_funcs_string); @@ -1807,8 +1357,25 @@ override_options (void) align_functions = processor_target_table[ix86_tune].align_func; } + /* Validate -mpreferred-stack-boundary= value, or provide default. + The default of 128 bits is for Pentium III's SSE __m128, but we + don't want additional code to keep the stack aligned when + optimizing for code size. */ + ix86_preferred_stack_boundary = (optimize_size + ? TARGET_64BIT ? 128 : 32 + : 128); + if (ix86_preferred_stack_boundary_string) + { + i = atoi (ix86_preferred_stack_boundary_string); + if (i < (TARGET_64BIT ? 4 : 2) || i > 12) + error ("-mpreferred-stack-boundary=%d is not between %d and 12", i, + TARGET_64BIT ? 4 : 2); + else + ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT; + } + /* Validate -mbranch-cost= value, or provide default. */ - ix86_branch_cost = ix86_cost->branch_cost; + ix86_branch_cost = processor_target_table[ix86_tune].cost->branch_cost; if (ix86_branch_cost_string) { i = atoi (ix86_branch_cost_string); @@ -1817,21 +1384,11 @@ override_options (void) else ix86_branch_cost = i; } - if (ix86_section_threshold_string) - { - i = atoi (ix86_section_threshold_string); - if (i < 0) - error ("-mlarge-data-threshold=%d is negative", i); - else - ix86_section_threshold = i; - } if (ix86_tls_dialect_string) { if (strcmp (ix86_tls_dialect_string, "gnu") == 0) ix86_tls_dialect = TLS_DIALECT_GNU; - else if (strcmp (ix86_tls_dialect_string, "gnu2") == 0) - ix86_tls_dialect = TLS_DIALECT_GNU2; else if (strcmp (ix86_tls_dialect_string, "sun") == 0) ix86_tls_dialect = TLS_DIALECT_SUN; else @@ -1840,14 +1397,12 @@ override_options (void) } /* Keep nonleaf frame pointers. */ - if (flag_omit_frame_pointer) - target_flags &= ~MASK_OMIT_LEAF_FRAME_POINTER; - else if (TARGET_OMIT_LEAF_FRAME_POINTER) + if (TARGET_OMIT_LEAF_FRAME_POINTER) flag_omit_frame_pointer = 1; /* If we're doing fast math, we don't care about comparison order wrt NaNs. This lets us use a shorter comparison sequence. */ - if (flag_finite_math_only) + if (flag_unsafe_math_optimizations) target_flags &= ~MASK_IEEE_FP; /* If the architecture always has an FPU, turn off NO_FANCY_MATH_387, @@ -1855,11 +1410,6 @@ override_options (void) if (x86_arch_always_fancy_math_387 & (1 << ix86_arch)) target_flags &= ~MASK_NO_FANCY_MATH_387; - /* Likewise, if the target doesn't have a 387, or we've specified - software floating point, don't use 387 inline intrinsics. */ - if (!TARGET_80387) - target_flags |= MASK_NO_FANCY_MATH_387; - /* Turn on SSE2 builtins for -msse3. */ if (TARGET_SSE3) target_flags |= MASK_SSE2; @@ -1868,61 +1418,25 @@ override_options (void) if (TARGET_SSE2) target_flags |= MASK_SSE; - /* Turn on MMX builtins for -msse. */ - if (TARGET_SSE) - { - target_flags |= MASK_MMX & ~target_flags_explicit; - x86_prefetch_sse = true; - } - - /* Turn on MMX builtins for 3Dnow. */ - if (TARGET_3DNOW) - target_flags |= MASK_MMX; - if (TARGET_64BIT) { if (TARGET_ALIGN_DOUBLE) error ("-malign-double makes no sense in the 64bit mode"); if (TARGET_RTD) error ("-mrtd calling convention not supported in the 64bit mode"); - - /* Enable by default the SSE and MMX builtins. Do allow the user to - explicitly disable any of these. In particular, disabling SSE and - MMX for kernel code is extremely useful. */ - target_flags - |= ((MASK_SSE2 | MASK_SSE | MASK_MMX | MASK_128BIT_LONG_DOUBLE) - & ~target_flags_explicit); + /* Enable by default the SSE and MMX builtins. */ + target_flags |= (MASK_SSE2 | MASK_SSE | MASK_MMX | MASK_128BIT_LONG_DOUBLE); + ix86_fpmath = FPMATH_SSE; } else { + ix86_fpmath = FPMATH_387; /* i386 ABI does not specify red zone. It still makes sense to use it when programmer takes care to stack from being destroyed. */ if (!(target_flags_explicit & MASK_NO_RED_ZONE)) target_flags |= MASK_NO_RED_ZONE; } - /* Validate -mpreferred-stack-boundary= value, or provide default. - The default of 128 bits is for Pentium III's SSE __m128. We can't - change it because of optimize_size. Otherwise, we can't mix object - files compiled with -Os and -On. */ - ix86_preferred_stack_boundary = 128; - if (ix86_preferred_stack_boundary_string) - { - i = atoi (ix86_preferred_stack_boundary_string); - if (i < (TARGET_64BIT ? 4 : 2) || i > 12) - error ("-mpreferred-stack-boundary=%d is not between %d and 12", i, - TARGET_64BIT ? 4 : 2); - else - ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT; - } - - /* Accept -msseregparm only if at least SSE support is enabled. */ - if (TARGET_SSEREGPARM - && ! TARGET_SSE) - error ("-msseregparm used without SSE enabled"); - - ix86_fpmath = TARGET_FPMATH_DEFAULT; - if (ix86_fpmath_string != 0) { if (! strcmp (ix86_fpmath_string, "387")) @@ -1931,7 +1445,7 @@ override_options (void) { if (!TARGET_SSE) { - warning (0, "SSE instruction set disabled, using 387 arithmetics"); + warning ("SSE instruction set disabled, using 387 arithmetics"); ix86_fpmath = FPMATH_387; } else @@ -1942,12 +1456,12 @@ override_options (void) { if (!TARGET_SSE) { - warning (0, "SSE instruction set disabled, using 387 arithmetics"); + warning ("SSE instruction set disabled, using 387 arithmetics"); ix86_fpmath = FPMATH_387; } else if (!TARGET_80387) { - warning (0, "387 instruction set disabled, using SSE arithmetics"); + warning ("387 instruction set disabled, using SSE arithmetics"); ix86_fpmath = FPMATH_SSE; } else @@ -1957,30 +1471,28 @@ override_options (void) error ("bad value (%s) for -mfpmath= switch", ix86_fpmath_string); } - /* If the i387 is disabled, then do not return values in it. */ - if (!TARGET_80387) - target_flags &= ~MASK_FLOAT_RETURNS; + /* It makes no sense to ask for just SSE builtins, so MMX is also turned + on by -msse. */ + if (TARGET_SSE) + { + target_flags |= MASK_MMX; + x86_prefetch_sse = true; + } + /* If it has 3DNow! it also has MMX so MMX is also turned on by -m3dnow */ + if (TARGET_3DNOW) + { + target_flags |= MASK_MMX; + /* If we are targeting the Athlon architecture, enable the 3Dnow/MMX + extensions it adds. */ + if (x86_3dnow_a & (1 << ix86_arch)) + target_flags |= MASK_3DNOW_A; + } if ((x86_accumulate_outgoing_args & TUNEMASK) && !(target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS) && !optimize_size) target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS; - /* ??? Unwind info is not correct around the CFG unless either a frame - pointer is present or M_A_O_A is set. Fixing this requires rewriting - unwind info generation to be aware of the CFG and propagating states - around edges. */ - if ((flag_unwind_tables || flag_asynchronous_unwind_tables - || flag_exceptions || flag_non_call_exceptions) - && flag_omit_frame_pointer - && !(target_flags & MASK_ACCUMULATE_OUTGOING_ARGS)) - { - if (target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS) - warning (0, "unwind tables currently require either a frame pointer " - "or -maccumulate-outgoing-args for correctness"); - target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS; - } - /* Figure out what ASM_GENERATE_INTERNAL_LABEL builds as a prefix. */ { char *p; @@ -1989,191 +1501,8 @@ override_options (void) internal_label_prefix_len = p - internal_label_prefix; *p = '\0'; } - - /* When scheduling description is not available, disable scheduler pass - so it won't slow down the compilation and make x87 code slower. */ - if (!TARGET_SCHEDULE) - flag_schedule_insns_after_reload = flag_schedule_insns = 0; } -/* switch to the appropriate section for output of DECL. - DECL is either a `VAR_DECL' node or a constant of some sort. - RELOC indicates whether forming the initial value of DECL requires - link-time relocations. */ - -static section * -x86_64_elf_select_section (tree decl, int reloc, - unsigned HOST_WIDE_INT align) -{ - if ((ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_MEDIUM_PIC) - && ix86_in_large_data_p (decl)) - { - const char *sname = NULL; - unsigned int flags = SECTION_WRITE; - switch (categorize_decl_for_section (decl, reloc)) - { - case SECCAT_DATA: - sname = ".ldata"; - break; - case SECCAT_DATA_REL: - sname = ".ldata.rel"; - break; - case SECCAT_DATA_REL_LOCAL: - sname = ".ldata.rel.local"; - break; - case SECCAT_DATA_REL_RO: - sname = ".ldata.rel.ro"; - break; - case SECCAT_DATA_REL_RO_LOCAL: - sname = ".ldata.rel.ro.local"; - break; - case SECCAT_BSS: - sname = ".lbss"; - flags |= SECTION_BSS; - break; - case SECCAT_RODATA: - case SECCAT_RODATA_MERGE_STR: - case SECCAT_RODATA_MERGE_STR_INIT: - case SECCAT_RODATA_MERGE_CONST: - sname = ".lrodata"; - flags = 0; - break; - case SECCAT_SRODATA: - case SECCAT_SDATA: - case SECCAT_SBSS: - gcc_unreachable (); - case SECCAT_TEXT: - case SECCAT_TDATA: - case SECCAT_TBSS: - /* We don't split these for medium model. Place them into - default sections and hope for best. */ - break; - } - if (sname) - { - /* We might get called with string constants, but get_named_section - doesn't like them as they are not DECLs. Also, we need to set - flags in that case. */ - if (!DECL_P (decl)) - return get_section (sname, flags, NULL); - return get_named_section (decl, sname, reloc); - } - } - return default_elf_select_section (decl, reloc, align); -} - -/* Build up a unique section name, expressed as a - STRING_CST node, and assign it to DECL_SECTION_NAME (decl). - RELOC indicates whether the initial value of EXP requires - link-time relocations. */ - -static void -x86_64_elf_unique_section (tree decl, int reloc) -{ - if ((ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_MEDIUM_PIC) - && ix86_in_large_data_p (decl)) - { - const char *prefix = NULL; - /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */ - bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP; - - switch (categorize_decl_for_section (decl, reloc)) - { - case SECCAT_DATA: - case SECCAT_DATA_REL: - case SECCAT_DATA_REL_LOCAL: - case SECCAT_DATA_REL_RO: - case SECCAT_DATA_REL_RO_LOCAL: - prefix = one_only ? ".gnu.linkonce.ld." : ".ldata."; - break; - case SECCAT_BSS: - prefix = one_only ? ".gnu.linkonce.lb." : ".lbss."; - break; - case SECCAT_RODATA: - case SECCAT_RODATA_MERGE_STR: - case SECCAT_RODATA_MERGE_STR_INIT: - case SECCAT_RODATA_MERGE_CONST: - prefix = one_only ? ".gnu.linkonce.lr." : ".lrodata."; - break; - case SECCAT_SRODATA: - case SECCAT_SDATA: - case SECCAT_SBSS: - gcc_unreachable (); - case SECCAT_TEXT: - case SECCAT_TDATA: - case SECCAT_TBSS: - /* We don't split these for medium model. Place them into - default sections and hope for best. */ - break; - } - if (prefix) - { - const char *name; - size_t nlen, plen; - char *string; - plen = strlen (prefix); - - name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - name = targetm.strip_name_encoding (name); - nlen = strlen (name); - - string = alloca (nlen + plen + 1); - memcpy (string, prefix, plen); - memcpy (string + plen, name, nlen + 1); - - DECL_SECTION_NAME (decl) = build_string (nlen + plen, string); - return; - } - } - default_unique_section (decl, reloc); -} - -#ifdef COMMON_ASM_OP -/* This says how to output assembler code to declare an - uninitialized external linkage data object. - - For medium model x86-64 we need to use .largecomm opcode for - large objects. */ -void -x86_elf_aligned_common (FILE *file, - const char *name, unsigned HOST_WIDE_INT size, - int align) -{ - if ((ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_MEDIUM_PIC) - && size > (unsigned int)ix86_section_threshold) - fprintf (file, ".largecomm\t"); - else - fprintf (file, "%s", COMMON_ASM_OP); - assemble_name (file, name); - fprintf (file, ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", - size, align / BITS_PER_UNIT); -} - -/* Utility function for targets to use in implementing - ASM_OUTPUT_ALIGNED_BSS. */ - -void -x86_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED, - const char *name, unsigned HOST_WIDE_INT size, - int align) -{ - if ((ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_MEDIUM_PIC) - && size > (unsigned int)ix86_section_threshold) - switch_to_section (get_named_section (decl, ".lbss", 0)); - else - switch_to_section (bss_section); - ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); -#ifdef ASM_DECLARE_OBJECT_NAME - last_assemble_variable_decl = decl; - ASM_DECLARE_OBJECT_NAME (file, name, decl); -#else - /* Standard thing is just output label for the object. */ - ASM_OUTPUT_LABEL (file, name); -#endif /* ASM_DECLARE_OBJECT_NAME */ - ASM_OUTPUT_SKIP (file, size ? size : 1); -} -#endif - void optimization_options (int level, int size ATTRIBUTE_UNUSED) { @@ -2184,11 +1513,6 @@ optimization_options (int level, int size ATTRIBUTE_UNUSED) flag_schedule_insns = 0; #endif - if (TARGET_MACHO) - /* The Darwin libraries never set errno, so we might as well - avoid calling them when that's the only reason we would. */ - flag_errno_math = 0; - /* The default values of these switches depend on the TARGET_64BIT that is not known at this moment. Mark these values with 2 and let user the to override these. In case there is no command line option @@ -2197,9 +1521,6 @@ optimization_options (int level, int size ATTRIBUTE_UNUSED) flag_omit_frame_pointer = 2; flag_pcc_struct_return = 2; flag_asynchronous_unwind_tables = 2; -#ifdef SUBTARGET_OPTIMIZATION_OPTIONS - SUBTARGET_OPTIMIZATION_OPTIONS; -#endif } /* Table of valid machine attributes. */ @@ -2208,31 +1529,22 @@ const struct attribute_spec ix86_attribute_table[] = /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ /* Stdcall attribute says callee is responsible for popping arguments if they are not variable. */ - { "stdcall", 0, 0, false, true, true, ix86_handle_cconv_attribute }, + { "stdcall", 0, 0, false, true, true, ix86_handle_cdecl_attribute }, /* Fastcall attribute says callee is responsible for popping arguments if they are not variable. */ - { "fastcall", 0, 0, false, true, true, ix86_handle_cconv_attribute }, + { "fastcall", 0, 0, false, true, true, ix86_handle_cdecl_attribute }, /* Cdecl attribute says the callee is a normal C declaration */ - { "cdecl", 0, 0, false, true, true, ix86_handle_cconv_attribute }, + { "cdecl", 0, 0, false, true, true, ix86_handle_cdecl_attribute }, /* Regparm attribute specifies how many integer arguments are to be passed in registers. */ - { "regparm", 1, 1, false, true, true, ix86_handle_cconv_attribute }, - /* Sseregparm attribute says we are using x86_64 calling conventions - for FP arguments. */ - { "sseregparm", 0, 0, false, true, true, ix86_handle_cconv_attribute }, - /* force_align_arg_pointer says this function realigns the stack at entry. */ - { (const char *)&ix86_force_align_arg_pointer_string, 0, 0, - false, true, true, ix86_handle_cconv_attribute }, -#if TARGET_DLLIMPORT_DECL_ATTRIBUTES - { "dllimport", 0, 0, false, false, false, handle_dll_attribute }, - { "dllexport", 0, 0, false, false, false, handle_dll_attribute }, + { "regparm", 1, 1, false, true, true, ix86_handle_regparm_attribute }, +#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES + { "dllimport", 0, 0, false, false, false, ix86_handle_dll_attribute }, + { "dllexport", 0, 0, false, false, false, ix86_handle_dll_attribute }, { "shared", 0, 0, true, false, false, ix86_handle_shared_attribute }, #endif { "ms_struct", 0, 0, false, false, false, ix86_handle_struct_attribute }, { "gcc_struct", 0, 0, false, false, false, ix86_handle_struct_attribute }, -#ifdef SUBTARGET_ATTRIBUTE_TABLE - SUBTARGET_ATTRIBUTE_TABLE, -#endif { NULL, 0, 0, false, false, false, NULL } }; @@ -2243,44 +1555,19 @@ const struct attribute_spec ix86_attribute_table[] = static bool ix86_function_ok_for_sibcall (tree decl, tree exp) { - tree func; - rtx a, b; - /* If we are generating position-independent code, we cannot sibcall optimize any indirect call, or a direct call to a global function, as the PLT requires %ebx be live. */ - if (!TARGET_64BIT && flag_pic && (!decl || !targetm.binds_local_p (decl))) + if (!TARGET_64BIT && flag_pic && (!decl || TREE_PUBLIC (decl))) return false; - if (decl) - func = decl; - else - { - func = TREE_TYPE (TREE_OPERAND (exp, 0)); - if (POINTER_TYPE_P (func)) - func = TREE_TYPE (func); - } - - /* Check that the return value locations are the same. Like - if we are returning floats on the 80387 register stack, we cannot + /* If we are returning floats on the 80387 register stack, we cannot make a sibcall from a function that doesn't return a float to a function that does or, conversely, from a function that does return a float to a function that doesn't; the necessary stack adjustment - would not be executed. This is also the place we notice - differences in the return value ABI. Note that it is ok for one - of the functions to have void return type as long as the return - value of the other is passed in a register. */ - a = ix86_function_value (TREE_TYPE (exp), func, false); - b = ix86_function_value (TREE_TYPE (DECL_RESULT (cfun->decl)), - cfun->decl, false); - if (STACK_REG_P (a) || STACK_REG_P (b)) - { - if (!rtx_equal_p (a, b)) - return false; - } - else if (VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl)))) - ; - else if (!rtx_equal_p (a, b)) + would not be executed. */ + if (STACK_REG_P (ix86_function_value (TREE_TYPE (exp))) + != STACK_REG_P (ix86_function_value (TREE_TYPE (DECL_RESULT (cfun->decl))))) return false; /* If this call is indirect, we'll need to be able to use a call-clobbered @@ -2303,134 +1590,96 @@ ix86_function_ok_for_sibcall (tree decl, tree exp) } } -#if TARGET_DLLIMPORT_DECL_ATTRIBUTES - /* Dllimport'd functions are also called indirectly. */ - if (decl && DECL_DLLIMPORT_P (decl) - && ix86_function_regparm (TREE_TYPE (decl), NULL) >= 3) - return false; -#endif - - /* If we forced aligned the stack, then sibcalling would unalign the - stack, which may break the called function. */ - if (cfun->machine->force_align_arg_pointer) - return false; - /* Otherwise okay. That also includes certain types of indirect calls. */ return true; } -/* Handle "cdecl", "stdcall", "fastcall", "regparm" and "sseregparm" - calling convention attributes; +/* Handle a "cdecl", "stdcall", or "fastcall" attribute; arguments as in struct attribute_spec.handler. */ - static tree -ix86_handle_cconv_attribute (tree *node, tree name, - tree args, - int flags ATTRIBUTE_UNUSED, - bool *no_add_attrs) +ix86_handle_cdecl_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (TREE_CODE (*node) != FUNCTION_TYPE && TREE_CODE (*node) != METHOD_TYPE && TREE_CODE (*node) != FIELD_DECL && TREE_CODE (*node) != TYPE_DECL) { - warning (OPT_Wattributes, "%qs attribute only applies to functions", + warning ("`%s' attribute only applies to functions", IDENTIFIER_POINTER (name)); *no_add_attrs = true; - return NULL_TREE; + } + else + { + if (is_attribute_p ("fastcall", name)) + { + if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node))) + { + error ("fastcall and stdcall attributes are not compatible"); + } + else if (lookup_attribute ("regparm", TYPE_ATTRIBUTES (*node))) + { + error ("fastcall and regparm attributes are not compatible"); + } + } + else if (is_attribute_p ("stdcall", name)) + { + if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node))) + { + error ("fastcall and stdcall attributes are not compatible"); + } + } } - /* Can combine regparm with all attributes but fastcall. */ - if (is_attribute_p ("regparm", name)) + if (TARGET_64BIT) { - tree cst; + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } - if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node))) - { - error ("fastcall and regparm attributes are not compatible"); - } + return NULL_TREE; +} + +/* Handle a "regparm" attribute; + arguments as in struct attribute_spec.handler. */ +static tree +ix86_handle_regparm_attribute (tree *node, tree name, tree args, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_TYPE + && TREE_CODE (*node) != METHOD_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else + { + tree cst; cst = TREE_VALUE (args); if (TREE_CODE (cst) != INTEGER_CST) { - warning (OPT_Wattributes, - "%qs attribute requires an integer constant argument", + warning ("`%s' attribute requires an integer constant argument", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } else if (compare_tree_int (cst, REGPARM_MAX) > 0) { - warning (OPT_Wattributes, "argument to %qs attribute larger than %d", + warning ("argument to `%s' attribute larger than %d", IDENTIFIER_POINTER (name), REGPARM_MAX); *no_add_attrs = true; } - if (!TARGET_64BIT - && lookup_attribute (ix86_force_align_arg_pointer_string, - TYPE_ATTRIBUTES (*node)) - && compare_tree_int (cst, REGPARM_MAX-1)) + if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node))) { - error ("%s functions limited to %d register parameters", - ix86_force_align_arg_pointer_string, REGPARM_MAX-1); - } - - return NULL_TREE; - } - - if (TARGET_64BIT) - { - warning (OPT_Wattributes, "%qs attribute ignored", - IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - return NULL_TREE; - } - - /* Can combine fastcall with stdcall (redundant) and sseregparm. */ - if (is_attribute_p ("fastcall", name)) - { - if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node))) - { - error ("fastcall and cdecl attributes are not compatible"); - } - if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node))) - { - error ("fastcall and stdcall attributes are not compatible"); - } - if (lookup_attribute ("regparm", TYPE_ATTRIBUTES (*node))) - { error ("fastcall and regparm attributes are not compatible"); } } - /* Can combine stdcall with fastcall (redundant), regparm and - sseregparm. */ - else if (is_attribute_p ("stdcall", name)) - { - if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node))) - { - error ("stdcall and cdecl attributes are not compatible"); - } - if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node))) - { - error ("stdcall and fastcall attributes are not compatible"); - } - } - - /* Can combine cdecl with regparm and sseregparm. */ - else if (is_attribute_p ("cdecl", name)) - { - if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node))) - { - error ("stdcall and cdecl attributes are not compatible"); - } - if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node))) - { - error ("fastcall and cdecl attributes are not compatible"); - } - } - - /* Can combine sseregparm with all attributes. */ - return NULL_TREE; } @@ -2447,27 +1696,22 @@ ix86_comp_type_attributes (tree type1, tree type2) if (TREE_CODE (type1) != FUNCTION_TYPE) return 1; - /* Check for mismatched fastcall/regparm types. */ - if ((!lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type1)) - != !lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type2))) - || (ix86_function_regparm (type1, NULL) - != ix86_function_regparm (type2, NULL))) - return 0; - - /* Check for mismatched sseregparm types. */ - if (!lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type1)) - != !lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type2))) + /* Check for mismatched fastcall types */ + if (!lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type1)) + != !lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type2))) return 0; /* Check for mismatched return types (cdecl vs stdcall). */ if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1)) != !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2))) return 0; - + if (ix86_function_regparm (type1, NULL) + != ix86_function_regparm (type2, NULL)) + return 0; return 1; } -/* Return the regparm value for a function with the indicated TYPE and DECL. +/* Return the regparm value for a fuctio with the indicated TYPE and DECL. DECL may be NULL when calling function indirectly or considering a libcall. */ @@ -2500,91 +1744,19 @@ ix86_function_regparm (tree type, tree decl) struct cgraph_local_info *i = cgraph_local_info (decl); if (i && i->local) { - int local_regparm, globals = 0, regno; - - /* Make sure no regparm register is taken by a global register - variable. */ - for (local_regparm = 0; local_regparm < 3; local_regparm++) - if (global_regs[local_regparm]) - break; /* We can't use regparm(3) for nested functions as these use static chain pointer in third argument. */ - if (local_regparm == 3 - && decl_function_context (decl) - && !DECL_NO_STATIC_CHAIN (decl)) - local_regparm = 2; - /* If the function realigns its stackpointer, the - prologue will clobber %ecx. If we've already - generated code for the callee, the callee - DECL_STRUCT_FUNCTION is gone, so we fall back to - scanning the attributes for the self-realigning - property. */ - if ((DECL_STRUCT_FUNCTION (decl) - && DECL_STRUCT_FUNCTION (decl)->machine->force_align_arg_pointer) - || (!DECL_STRUCT_FUNCTION (decl) - && lookup_attribute (ix86_force_align_arg_pointer_string, - TYPE_ATTRIBUTES (TREE_TYPE (decl))))) - local_regparm = 2; - /* Each global register variable increases register preassure, - so the more global reg vars there are, the smaller regparm - optimization use, unless requested by the user explicitly. */ - for (regno = 0; regno < 6; regno++) - if (global_regs[regno]) - globals++; - local_regparm - = globals < local_regparm ? local_regparm - globals : 0; - - if (local_regparm > regparm) - regparm = local_regparm; + if (DECL_CONTEXT (decl) && !DECL_NO_STATIC_CHAIN (decl)) + regparm = 2; + else + regparm = 3; } } } return regparm; } -/* Return 1 or 2, if we can pass up to SSE_REGPARM_MAX SFmode (1) and - DFmode (2) arguments in SSE registers for a function with the - indicated TYPE and DECL. DECL may be NULL when calling function - indirectly or considering a libcall. Otherwise return 0. */ - -static int -ix86_function_sseregparm (tree type, tree decl) -{ - /* Use SSE registers to pass SFmode and DFmode arguments if requested - by the sseregparm attribute. */ - if (TARGET_SSEREGPARM - || (type - && lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type)))) - { - if (!TARGET_SSE) - { - if (decl) - error ("Calling %qD with attribute sseregparm without " - "SSE/SSE2 enabled", decl); - else - error ("Calling %qT with attribute sseregparm without " - "SSE/SSE2 enabled", type); - return 0; - } - - return 2; - } - - /* For local functions, pass up to SSE_REGPARM_MAX SFmode - (and DFmode for SSE2) arguments in SSE registers, - even for 32-bit targets. */ - if (!TARGET_64BIT && decl - && TARGET_SSE_MATH && flag_unit_at_a_time && !profile_flag) - { - struct cgraph_local_info *i = cgraph_local_info (decl); - if (i && i->local) - return TARGET_SSE2 ? 2 : 1; - } - - return 0; -} - -/* Return true if EAX is live at the start of the function. Used by +/* Return true if EAX is live at the start of the function. Used by ix86_expand_prologue to determine if we need special help before calling allocate_stack_worker. */ @@ -2597,7 +1769,7 @@ ix86_eax_live_at_start_p (void) to correct at this point. This gives false positives for broken functions that might use uninitialized data that happens to be allocated in eax, but who cares? */ - return REGNO_REG_SET_P (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end, 0); + return REGNO_REG_SET_P (ENTRY_BLOCK_PTR->global_live_at_end, 0); } /* Value is the number of bytes of arguments automatically @@ -2640,8 +1812,7 @@ ix86_return_pops_args (tree fundecl, tree funtype, int size) /* Lose any fake structure return argument if it is passed on the stack. */ if (aggregate_value_p (TREE_TYPE (funtype), fundecl) - && !TARGET_64BIT - && !KEEP_AGGREGATE_RETURN_POINTER) + && !TARGET_64BIT) { int nregs = ix86_function_regparm (funtype, fundecl); @@ -2660,29 +1831,10 @@ ix86_function_arg_regno_p (int regno) { int i; if (!TARGET_64BIT) - { - if (TARGET_MACHO) - return (regno < REGPARM_MAX - || (TARGET_SSE && SSE_REGNO_P (regno) && !fixed_regs[regno])); - else - return (regno < REGPARM_MAX - || (TARGET_MMX && MMX_REGNO_P (regno) - && (regno < FIRST_MMX_REG + MMX_REGPARM_MAX)) - || (TARGET_SSE && SSE_REGNO_P (regno) - && (regno < FIRST_SSE_REG + SSE_REGPARM_MAX))); - } - - if (TARGET_MACHO) - { - if (SSE_REGNO_P (regno) && TARGET_SSE) - return true; - } - else - { - if (TARGET_SSE && SSE_REGNO_P (regno) - && (regno < FIRST_SSE_REG + SSE_REGPARM_MAX)) - return true; - } + return (regno < REGPARM_MAX + || (TARGET_SSE && SSE_REGNO_P (regno) && !fixed_regs[regno])); + if (SSE_REGNO_P (regno) && TARGET_SSE) + return true; /* RAX is used as hidden argument to va_arg functions. */ if (!regno) return true; @@ -2692,21 +1844,6 @@ ix86_function_arg_regno_p (int regno) return false; } -/* Return if we do not know how to pass TYPE solely in registers. */ - -static bool -ix86_must_pass_in_stack (enum machine_mode mode, tree type) -{ - if (must_pass_in_stack_var_size_or_pad (mode, type)) - return true; - - /* For 32-bit, we want TImode aggregates to go on the stack. But watch out! - The layout_type routine is crafty and tries to trick us into passing - currently unsupported vector types on the stack by using TImode. */ - return (!TARGET_64BIT && mode == TImode - && type && TREE_CODE (type) != VECTOR_TYPE); -} - /* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. */ @@ -2737,17 +1874,17 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ *cum = zero_cum; /* Set up the number of registers to use for passing arguments. */ - cum->nregs = ix86_regparm; - if (TARGET_SSE) - cum->sse_nregs = SSE_REGPARM_MAX; - if (TARGET_MMX) - cum->mmx_nregs = MMX_REGPARM_MAX; + if (fntype) + cum->nregs = ix86_function_regparm (fntype, fndecl); + else + cum->nregs = ix86_regparm; + cum->sse_nregs = SSE_REGPARM_MAX; + cum->mmx_nregs = MMX_REGPARM_MAX; cum->warn_sse = true; cum->warn_mmx = true; cum->maybe_vaarg = false; - /* Use ecx and edx registers if function has fastcall attribute, - else look for regparm information. */ + /* Use ecx and edx registers if function has fastcall attribute */ if (fntype && !TARGET_64BIT) { if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype))) @@ -2755,20 +1892,15 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ cum->nregs = 2; cum->fastcall = 1; } - else - cum->nregs = ix86_function_regparm (fntype, fndecl); } - /* Set up the number of SSE registers used for passing SFmode - and DFmode arguments. Warn for mismatching ABI. */ - cum->float_in_sse = ix86_function_sseregparm (fntype, fndecl); /* Determine if this function has variable arguments. This is indicated by the last argument being 'void_type_mode' if there are no variable arguments. If there are variable arguments, then - we won't pass anything in registers in 32-bit mode. */ + we won't pass anything in registers */ - if (cum->nregs || cum->mmx_nregs || cum->sse_nregs) + if (cum->nregs || !TARGET_MMX || !TARGET_SSE) { for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; param != 0; param = next_param) @@ -2784,7 +1916,6 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ cum->warn_sse = 0; cum->warn_mmx = 0; cum->fastcall = 0; - cum->float_in_sse = 0; } cum->maybe_vaarg = true; } @@ -2792,7 +1923,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ } if ((!fntype && !libname) || (fntype && !TYPE_ARG_TYPES (fntype))) - cum->maybe_vaarg = true; + cum->maybe_vaarg = 1; if (TARGET_DEBUG_ARG) fprintf (stderr, ", nregs=%d )\n", cum->nregs); @@ -2800,71 +1931,6 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ return; } -/* Return the "natural" mode for TYPE. In most cases, this is just TYPE_MODE. - But in the case of vector types, it is some vector mode. - - When we have only some of our vector isa extensions enabled, then there - are some modes for which vector_mode_supported_p is false. For these - modes, the generic vector support in gcc will choose some non-vector mode - in order to implement the type. By computing the natural mode, we'll - select the proper ABI location for the operand and not depend on whatever - the middle-end decides to do with these vector types. */ - -static enum machine_mode -type_natural_mode (tree type) -{ - enum machine_mode mode = TYPE_MODE (type); - - if (TREE_CODE (type) == VECTOR_TYPE && !VECTOR_MODE_P (mode)) - { - HOST_WIDE_INT size = int_size_in_bytes (type); - if ((size == 8 || size == 16) - /* ??? Generic code allows us to create width 1 vectors. Ignore. */ - && TYPE_VECTOR_SUBPARTS (type) > 1) - { - enum machine_mode innermode = TYPE_MODE (TREE_TYPE (type)); - - if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE) - mode = MIN_MODE_VECTOR_FLOAT; - else - mode = MIN_MODE_VECTOR_INT; - - /* Get the mode which has this inner mode and number of units. */ - for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - if (GET_MODE_NUNITS (mode) == TYPE_VECTOR_SUBPARTS (type) - && GET_MODE_INNER (mode) == innermode) - return mode; - - gcc_unreachable (); - } - } - - return mode; -} - -/* We want to pass a value in REGNO whose "natural" mode is MODE. However, - this may not agree with the mode that the type system has chosen for the - register, which is ORIG_MODE. If ORIG_MODE is not BLKmode, then we can - go ahead and use it. Otherwise we have to build a PARALLEL instead. */ - -static rtx -gen_reg_or_parallel (enum machine_mode mode, enum machine_mode orig_mode, - unsigned int regno) -{ - rtx tmp; - - if (orig_mode != BLKmode) - tmp = gen_rtx_REG (orig_mode, regno); - else - { - tmp = gen_rtx_REG (mode, regno); - tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, const0_rtx); - tmp = gen_rtx_PARALLEL (orig_mode, gen_rtvec (1, tmp)); - } - - return tmp; -} - /* x86-64 register passing implementation. See x86-64 ABI for details. Goal of this code is to classify each 8bytes of incoming argument by the register class and assign registers accordingly. */ @@ -2898,14 +1964,9 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) return X86_64_INTEGER_CLASS; - /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class, - MEMORY is used. */ - if (class1 == X86_64_X87_CLASS - || class1 == X86_64_X87UP_CLASS - || class1 == X86_64_COMPLEX_X87_CLASS - || class2 == X86_64_X87_CLASS - || class2 == X86_64_X87UP_CLASS - || class2 == X86_64_COMPLEX_X87_CLASS) + /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */ + if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS + || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS) return X86_64_MEMORY_CLASS; /* Rule #6: Otherwise class SSE is used. */ @@ -2937,7 +1998,7 @@ classify_argument (enum machine_mode mode, tree type, return 0; if (mode != VOIDmode - && targetm.calls.must_pass_in_stack (mode, type)) + && MUST_PASS_IN_STACK (mode, type)) return 0; if (type && AGGREGATE_TYPE_P (type)) @@ -2962,21 +2023,21 @@ classify_argument (enum machine_mode mode, tree type, } /* Classify each field of record and merge classes. */ - switch (TREE_CODE (type)) + if (TREE_CODE (type) == RECORD_TYPE) { - case RECORD_TYPE: /* For classes first merge in the field of the subclasses. */ - if (TYPE_BINFO (type)) + if (TYPE_BINFO (type) != NULL && TYPE_BINFO_BASETYPES (type) != NULL) { - tree binfo, base_binfo; - int basenum; + tree bases = TYPE_BINFO_BASETYPES (type); + int n_bases = TREE_VEC_LENGTH (bases); + int i; - for (binfo = TYPE_BINFO (type), basenum = 0; - BINFO_BASE_ITERATE (binfo, basenum, base_binfo); basenum++) + for (i = 0; i < n_bases; ++i) { + tree binfo = TREE_VEC_ELT (bases, i); int num; - int offset = tree_low_cst (BINFO_OFFSET (base_binfo), 0) * 8; - tree type = BINFO_TYPE (base_binfo); + int offset = tree_low_cst (BINFO_OFFSET (binfo), 0) * 8; + tree type = BINFO_TYPE (binfo); num = classify_argument (TYPE_MODE (type), type, subclasses, @@ -2998,16 +2059,13 @@ classify_argument (enum machine_mode mode, tree type, { int num; - if (TREE_TYPE (field) == error_mark_node) - continue; - /* Bitfields are always classified as integer. Handle them early, since later code would consider them to be misaligned integers. */ if (DECL_BIT_FIELD (field)) { - for (i = (int_bit_position (field) + (bit_offset % 64)) / 8 / 8; - i < ((int_bit_position (field) + (bit_offset % 64)) + for (i = int_bit_position (field) / 8 / 8; + i < (int_bit_position (field) + tree_low_cst (DECL_SIZE (field), 0) + 63) / 8 / 8; i++) classes[i] = @@ -3032,45 +2090,61 @@ classify_argument (enum machine_mode mode, tree type, } } } - break; + } + /* Arrays are handled as small records. */ + else if (TREE_CODE (type) == ARRAY_TYPE) + { + int num; + num = classify_argument (TYPE_MODE (TREE_TYPE (type)), + TREE_TYPE (type), subclasses, bit_offset); + if (!num) + return 0; - case ARRAY_TYPE: - /* Arrays are handled as small records. */ - { - int num; - num = classify_argument (TYPE_MODE (TREE_TYPE (type)), - TREE_TYPE (type), subclasses, bit_offset); - if (!num) - return 0; + /* The partial classes are now full classes. */ + if (subclasses[0] == X86_64_SSESF_CLASS && bytes != 4) + subclasses[0] = X86_64_SSE_CLASS; + if (subclasses[0] == X86_64_INTEGERSI_CLASS && bytes != 4) + subclasses[0] = X86_64_INTEGER_CLASS; - /* The partial classes are now full classes. */ - if (subclasses[0] == X86_64_SSESF_CLASS && bytes != 4) - subclasses[0] = X86_64_SSE_CLASS; - if (subclasses[0] == X86_64_INTEGERSI_CLASS && bytes != 4) - subclasses[0] = X86_64_INTEGER_CLASS; + for (i = 0; i < words; i++) + classes[i] = subclasses[i % num]; + } + /* Unions are similar to RECORD_TYPE but offset is always 0. */ + else if (TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + { + /* For classes first merge in the field of the subclasses. */ + if (TYPE_BINFO (type) != NULL && TYPE_BINFO_BASETYPES (type) != NULL) + { + tree bases = TYPE_BINFO_BASETYPES (type); + int n_bases = TREE_VEC_LENGTH (bases); + int i; - for (i = 0; i < words; i++) - classes[i] = subclasses[i % num]; + for (i = 0; i < n_bases; ++i) + { + tree binfo = TREE_VEC_ELT (bases, i); + int num; + int offset = tree_low_cst (BINFO_OFFSET (binfo), 0) * 8; + tree type = BINFO_TYPE (binfo); - break; - } - case UNION_TYPE: - case QUAL_UNION_TYPE: - /* Unions are similar to RECORD_TYPE but offset is always 0. - */ - - /* Unions are not derived. */ - gcc_assert (!TYPE_BINFO (type) - || !BINFO_N_BASE_BINFOS (TYPE_BINFO (type))); + num = classify_argument (TYPE_MODE (type), + type, subclasses, + (offset + (bit_offset % 64)) % 256); + if (!num) + return 0; + for (i = 0; i < num; i++) + { + int pos = (offset + (bit_offset % 64)) / 8 / 8; + classes[i + pos] = + merge_classes (subclasses[i], classes[i + pos]); + } + } + } for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) { if (TREE_CODE (field) == FIELD_DECL) { int num; - - if (TREE_TYPE (field) == error_mark_node) - continue; - num = classify_argument (TYPE_MODE (TREE_TYPE (field)), TREE_TYPE (field), subclasses, bit_offset); @@ -3080,11 +2154,34 @@ classify_argument (enum machine_mode mode, tree type, classes[i] = merge_classes (subclasses[i], classes[i]); } } - break; - - default: - gcc_unreachable (); } + else if (TREE_CODE (type) == SET_TYPE) + { + if (bytes <= 4) + { + classes[0] = X86_64_INTEGERSI_CLASS; + return 1; + } + else if (bytes <= 8) + { + classes[0] = X86_64_INTEGER_CLASS; + return 1; + } + else if (bytes <= 12) + { + classes[0] = X86_64_INTEGER_CLASS; + classes[1] = X86_64_INTEGERSI_CLASS; + return 2; + } + else + { + classes[0] = X86_64_INTEGER_CLASS; + classes[1] = X86_64_INTEGER_CLASS; + return 2; + } + } + else + abort (); /* Final merger cleanup. */ for (i = 0; i < words; i++) @@ -3125,22 +2222,9 @@ classify_argument (enum machine_mode mode, tree type, return 0; } - /* for V1xx modes, just use the base mode */ - if (VECTOR_MODE_P (mode) - && GET_MODE_SIZE (GET_MODE_INNER (mode)) == bytes) - mode = GET_MODE_INNER (mode); - /* Classification of atomic types. */ switch (mode) { - case SDmode: - case DDmode: - classes[0] = X86_64_SSE_CLASS; - return 1; - case TDmode: - classes[0] = X86_64_SSE_CLASS; - classes[1] = X86_64_SSEUP_CLASS; - return 2; case DImode: case SImode: case HImode: @@ -3158,7 +2242,9 @@ classify_argument (enum machine_mode mode, tree type, classes[0] = classes[1] = X86_64_INTEGER_CLASS; return 2; case CTImode: - return 0; + classes[0] = classes[1] = X86_64_INTEGER_CLASS; + classes[2] = classes[3] = X86_64_INTEGER_CLASS; + return 4; case SFmode: if (!(bit_offset % 64)) classes[0] = X86_64_SSESF_CLASS; @@ -3173,22 +2259,21 @@ classify_argument (enum machine_mode mode, tree type, classes[1] = X86_64_X87UP_CLASS; return 2; case TFmode: - classes[0] = X86_64_SSE_CLASS; - classes[1] = X86_64_SSEUP_CLASS; - return 2; - case SCmode: - classes[0] = X86_64_SSE_CLASS; - return 1; + case TCmode: + return 0; + case XCmode: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + classes[2] = X86_64_X87_CLASS; + classes[3] = X86_64_X87UP_CLASS; + return 4; case DCmode: classes[0] = X86_64_SSEDF_CLASS; classes[1] = X86_64_SSEDF_CLASS; return 2; - case XCmode: - classes[0] = X86_64_COMPLEX_X87_CLASS; + case SCmode: + classes[0] = X86_64_SSE_CLASS; return 1; - case TCmode: - /* This modes is larger than 16 bytes. */ - return 0; case V4SFmode: case V4SImode: case V16QImode: @@ -3202,25 +2287,12 @@ classify_argument (enum machine_mode mode, tree type, case V2SImode: case V4HImode: case V8QImode: - classes[0] = X86_64_SSE_CLASS; - return 1; + return 0; case BLKmode: case VOIDmode: return 0; default: - gcc_assert (VECTOR_MODE_P (mode)); - - if (bytes > 16) - return 0; - - gcc_assert (GET_MODE_CLASS (GET_MODE_INNER (mode)) == MODE_INT); - - if (bit_offset + GET_MODE_BITSIZE (mode) <= 32) - classes[0] = X86_64_INTEGERSI_CLASS; - else - classes[0] = X86_64_INTEGER_CLASS; - classes[1] = X86_64_INTEGER_CLASS; - return 1 + (bytes > 8); + abort (); } } @@ -3257,27 +2329,18 @@ examine_argument (enum machine_mode mode, tree type, int in_return, if (!in_return) return 0; break; - case X86_64_COMPLEX_X87_CLASS: - return in_return ? 2 : 0; case X86_64_MEMORY_CLASS: - gcc_unreachable (); + abort (); } return 1; } - /* Construct container for the argument used by GCC interface. See FUNCTION_ARG for the detailed description. */ - static rtx -construct_container (enum machine_mode mode, enum machine_mode orig_mode, - tree type, int in_return, int nintregs, int nsseregs, - const int *intreg, int sse_regno) +construct_container (enum machine_mode mode, tree type, int in_return, + int nintregs, int nsseregs, const int * intreg, + int sse_regno) { - /* The following variables hold the static issued_error state. */ - static bool issued_sse_arg_error; - static bool issued_sse_ret_error; - static bool issued_x87_ret_error; - enum machine_mode tmpmode; int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); @@ -3306,48 +2369,11 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode, } if (!n) return NULL; - if (!examine_argument (mode, type, in_return, &needed_intregs, - &needed_sseregs)) + if (!examine_argument (mode, type, in_return, &needed_intregs, &needed_sseregs)) return NULL; if (needed_intregs > nintregs || needed_sseregs > nsseregs) return NULL; - /* We allowed the user to turn off SSE for kernel mode. Don't crash if - some less clueful developer tries to use floating-point anyway. */ - if (needed_sseregs && !TARGET_SSE) - { - if (in_return) - { - if (!issued_sse_ret_error) - { - error ("SSE register return with SSE disabled"); - issued_sse_ret_error = true; - } - } - else if (!issued_sse_arg_error) - { - error ("SSE register argument with SSE disabled"); - issued_sse_arg_error = true; - } - return NULL; - } - - /* Likewise, error if the ABI requires us to return values in the - x87 registers and the user specified -mno-80387. */ - if (!TARGET_80387 && in_return) - for (i = 0; i < n; i++) - if (class[i] == X86_64_X87_CLASS - || class[i] == X86_64_X87UP_CLASS - || class[i] == X86_64_COMPLEX_X87_CLASS) - { - if (!issued_x87_ret_error) - { - error ("x87 register return with x87 disabled"); - issued_x87_ret_error = true; - } - return NULL; - } - /* First construct simple cases. Avoid SCmode, since we want to use single register to pass this type. */ if (n == 1 && mode != SCmode) @@ -3359,15 +2385,14 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode, case X86_64_SSE_CLASS: case X86_64_SSESF_CLASS: case X86_64_SSEDF_CLASS: - return gen_reg_or_parallel (mode, orig_mode, SSE_REGNO (sse_regno)); + return gen_rtx_REG (mode, SSE_REGNO (sse_regno)); case X86_64_X87_CLASS: - case X86_64_COMPLEX_X87_CLASS: return gen_rtx_REG (mode, FIRST_STACK_REG); case X86_64_NO_CLASS: /* Zero sized array, struct or class. */ return NULL; default: - gcc_unreachable (); + abort (); } if (n == 2 && class[0] == X86_64_SSE_CLASS && class[1] == X86_64_SSEUP_CLASS && mode != BLKmode) @@ -3380,6 +2405,11 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode, && (mode == CDImode || mode == TImode || mode == TFmode) && intreg[0] + 1 == intreg[1]) return gen_rtx_REG (mode, intreg[0]); + if (n == 4 + && class[0] == X86_64_X87_CLASS && class[1] == X86_64_X87UP_CLASS + && class[2] == X86_64_X87_CLASS && class[3] == X86_64_X87UP_CLASS + && mode != BLKmode) + return gen_rtx_REG (XCmode, FIRST_STACK_REG); /* Otherwise figure out the entries of the PARALLEL. */ for (i = 0; i < n; i++) @@ -3433,14 +2463,9 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode, sse_regno++; break; default: - gcc_unreachable (); + abort (); } } - - /* Empty aligned struct, union or class. */ - if (nexps == 0) - return NULL; - ret = gen_rtx_PARALLEL (mode, rtvec_alloc (nexps)); for (i = 0; i < nexps; i++) XVECEXP (ret, 0, i) = exp [i]; @@ -3452,22 +2477,19 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode, (TYPE is null for libcalls where that information may not be available.) */ void -function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, - tree type, int named) +function_arg_advance (CUMULATIVE_ARGS *cum, /* current arg information */ + enum machine_mode mode, /* current arg mode */ + tree type, /* type of the argument or 0 if lib support */ + int named) /* whether or not the argument was named */ { int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; - if (type) - mode = type_natural_mode (type); - if (TARGET_DEBUG_ARG) - fprintf (stderr, "function_adv (sz=%d, wds=%2d, nregs=%d, ssenregs=%d, " - "mode=%s, named=%d)\n\n", - words, cum->words, cum->nregs, cum->sse_nregs, - GET_MODE_NAME (mode), named); - + fprintf (stderr, + "function_adv (sz=%d, wds=%2d, nregs=%d, ssenregs=%d, mode=%s, named=%d)\n\n", + words, cum->words, cum->nregs, cum->sse_nregs, GET_MODE_NAME (mode), named); if (TARGET_64BIT) { int int_nregs, sse_nregs; @@ -3485,20 +2507,32 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, } else { - switch (mode) + if (TARGET_SSE && SSE_REG_MODE_P (mode) + && (!type || !AGGREGATE_TYPE_P (type))) + { + cum->sse_words += words; + cum->sse_nregs -= 1; + cum->sse_regno += 1; + if (cum->sse_nregs <= 0) + { + cum->sse_nregs = 0; + cum->sse_regno = 0; + } + } + else if (TARGET_MMX && MMX_REG_MODE_P (mode) + && (!type || !AGGREGATE_TYPE_P (type))) + { + cum->mmx_words += words; + cum->mmx_nregs -= 1; + cum->mmx_regno += 1; + if (cum->mmx_nregs <= 0) + { + cum->mmx_nregs = 0; + cum->mmx_regno = 0; + } + } + else { - default: - break; - - case BLKmode: - if (bytes < 0) - break; - /* FALLTHRU */ - - case DImode: - case SImode: - case HImode: - case QImode: cum->words += words; cum->nregs -= words; cum->regno += words; @@ -3508,54 +2542,37 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, cum->nregs = 0; cum->regno = 0; } - break; + } + } + return; +} - case DFmode: - if (cum->float_in_sse < 2) - break; - case SFmode: - if (cum->float_in_sse < 1) - break; - /* FALLTHRU */ +/* A subroutine of function_arg. We want to pass a parameter whose nominal + type is MODE in REGNO. We try to minimize ABI variation, so MODE may not + actually be valid for REGNO with the current ISA. In this case, ALT_MODE + is used instead. It must be the same size as MODE, and must be known to + be valid for REGNO. Finally, ORIG_MODE is the original mode of the + parameter, as seen by the type system. This may be different from MODE + when we're mucking with things minimizing ABI variations. - case TImode: - case V16QImode: - case V8HImode: - case V4SImode: - case V2DImode: - case V4SFmode: - case V2DFmode: - if (!type || !AGGREGATE_TYPE_P (type)) - { - cum->sse_words += words; - cum->sse_nregs -= 1; - cum->sse_regno += 1; - if (cum->sse_nregs <= 0) - { - cum->sse_nregs = 0; - cum->sse_regno = 0; - } - } - break; + Returns a REG or a PARALLEL as appropriate. */ - case V8QImode: - case V4HImode: - case V2SImode: - case V2SFmode: - if (!type || !AGGREGATE_TYPE_P (type)) - { - cum->mmx_words += words; - cum->mmx_nregs -= 1; - cum->mmx_regno += 1; - if (cum->mmx_nregs <= 0) - { - cum->mmx_nregs = 0; - cum->mmx_regno = 0; - } - } - break; - } +static rtx +gen_reg_or_parallel (enum machine_mode mode, enum machine_mode alt_mode, + enum machine_mode orig_mode, unsigned int regno) +{ + rtx tmp; + + if (HARD_REGNO_MODE_OK (regno, mode)) + tmp = gen_rtx_REG (mode, regno); + else + { + tmp = gen_rtx_REG (alt_mode, regno); + tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, const0_rtx); + tmp = gen_rtx_PARALLEL (orig_mode, gen_rtvec (1, tmp)); } + + return tmp; } /* Define where to put the arguments to a function. @@ -3582,11 +2599,6 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode, int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; static bool warnedsse, warnedmmx; - /* To simplify the code below, represent vector types with a vector mode - even if MMX/SSE are not active. */ - if (type && TREE_CODE (type) == VECTOR_TYPE) - mode = type_natural_mode (type); - /* Handle a hidden AL argument containing number of registers for varargs x86-64 functions. For i386 ABI just return constm1_rtx to avoid any AL settings. */ @@ -3602,8 +2614,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode, return constm1_rtx; } if (TARGET_64BIT) - ret = construct_container (mode, orig_mode, type, 0, cum->nregs, - cum->sse_nregs, + ret = construct_container (mode, type, 0, cum->nregs, cum->sse_nregs, &x86_64_int_parameter_registers [cum->regno], cum->sse_regno); else @@ -3639,13 +2650,6 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode, ret = gen_rtx_REG (mode, regno); } break; - case DFmode: - if (cum->float_in_sse < 2) - break; - case SFmode: - if (cum->float_in_sse < 1) - break; - /* FALLTHRU */ case TImode: case V16QImode: case V8HImode: @@ -3655,14 +2659,14 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode, case V2DFmode: if (!type || !AGGREGATE_TYPE_P (type)) { - if (!TARGET_SSE && !warnedsse && cum->warn_sse) + if (!TARGET_SSE && !warnedmmx && cum->warn_sse) { warnedsse = true; - warning (0, "SSE vector argument without SSE enabled " + warning ("SSE vector argument without SSE enabled " "changes the ABI"); } if (cum->sse_nregs) - ret = gen_reg_or_parallel (mode, orig_mode, + ret = gen_reg_or_parallel (mode, TImode, orig_mode, cum->sse_regno + FIRST_SSE_REG); } break; @@ -3675,11 +2679,11 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode, if (!TARGET_MMX && !warnedmmx && cum->warn_mmx) { warnedmmx = true; - warning (0, "MMX vector argument without MMX enabled " + warning ("MMX vector argument without MMX enabled " "changes the ABI"); } if (cum->mmx_nregs) - ret = gen_reg_or_parallel (mode, orig_mode, + ret = gen_reg_or_parallel (mode, DImode, orig_mode, cum->mmx_regno + FIRST_MMX_REG); } break; @@ -3708,10 +2712,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode, the argument itself. The pointer is passed in whatever way is appropriate for passing a pointer to that type. */ -static bool -ix86_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED, - tree type, bool named ATTRIBUTE_UNUSED) +int +function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + tree type, int named ATTRIBUTE_UNUSED) { if (!TARGET_64BIT) return 0; @@ -3727,7 +2731,7 @@ ix86_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, } /* Return true when TYPE should be 128bit aligned for 32bit argument passing - ABI. Only called if TARGET_SSE. */ + ABI */ static bool contains_128bit_aligned_vector_p (tree type) { @@ -3741,44 +2745,44 @@ contains_128bit_aligned_vector_p (tree type) if (AGGREGATE_TYPE_P (type)) { /* Walk the aggregates recursively. */ - switch (TREE_CODE (type)) + if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) { - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - { - tree field; + tree field; - if (TYPE_BINFO (type)) - { - tree binfo, base_binfo; - int i; + if (TYPE_BINFO (type) != NULL + && TYPE_BINFO_BASETYPES (type) != NULL) + { + tree bases = TYPE_BINFO_BASETYPES (type); + int n_bases = TREE_VEC_LENGTH (bases); + int i; - for (binfo = TYPE_BINFO (type), i = 0; - BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) - if (contains_128bit_aligned_vector_p - (BINFO_TYPE (base_binfo))) - return true; - } - /* And now merge the fields of structure. */ - for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) == FIELD_DECL - && contains_128bit_aligned_vector_p (TREE_TYPE (field))) - return true; - } - break; - } + for (i = 0; i < n_bases; ++i) + { + tree binfo = TREE_VEC_ELT (bases, i); + tree type = BINFO_TYPE (binfo); - case ARRAY_TYPE: - /* Just for use if some languages passes arrays by value. */ + if (contains_128bit_aligned_vector_p (type)) + return true; + } + } + /* And now merge the fields of structure. */ + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL + && contains_128bit_aligned_vector_p (TREE_TYPE (field))) + return true; + } + } + /* Just for use if some languages passes arrays by value. */ + else if (TREE_CODE (type) == ARRAY_TYPE) + { if (contains_128bit_aligned_vector_p (TREE_TYPE (type))) return true; - break; - - default: - gcc_unreachable (); } + else + abort (); } return false; } @@ -3805,9 +2809,7 @@ ix86_function_arg_boundary (enum machine_mode mode, tree type) The handling here differs from field_alignment. ICC aligns MMX arguments to 4 byte boundaries, while structure fields are aligned to 8 byte boundaries. */ - if (!TARGET_SSE) - align = PARM_BOUNDARY; - else if (!type) + if (!type) { if (!SSE_REG_MODE_P (mode)) align = PARM_BOUNDARY; @@ -3827,31 +2829,15 @@ ix86_function_arg_boundary (enum machine_mode mode, tree type) bool ix86_function_value_regno_p (int regno) { - if (TARGET_MACHO) - { - if (!TARGET_64BIT) - { - return ((regno) == 0 - || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387) - || ((regno) == FIRST_SSE_REG && TARGET_SSE)); - } - return ((regno) == 0 || (regno) == FIRST_FLOAT_REG - || ((regno) == FIRST_SSE_REG && TARGET_SSE) - || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387)); - } - else + if (!TARGET_64BIT) { - if (regno == 0 - || (regno == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387) - || (regno == FIRST_SSE_REG && TARGET_SSE)) - return true; - - if (!TARGET_64BIT - && (regno == FIRST_MMX_REG && TARGET_MMX)) - return true; - - return false; + return ((regno) == 0 + || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387) + || ((regno) == FIRST_SSE_REG && TARGET_SSE)); } + return ((regno) == 0 || (regno) == FIRST_FLOAT_REG + || ((regno) == FIRST_SSE_REG && TARGET_SSE) + || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387)); } /* Define how to find the value returned by a function. @@ -3859,40 +2845,30 @@ ix86_function_value_regno_p (int regno) If the precise function being called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0. */ rtx -ix86_function_value (tree valtype, tree fntype_or_decl, - bool outgoing ATTRIBUTE_UNUSED) +ix86_function_value (tree valtype) { - enum machine_mode natmode = type_natural_mode (valtype); - if (TARGET_64BIT) { - rtx ret = construct_container (natmode, TYPE_MODE (valtype), valtype, - 1, REGPARM_MAX, SSE_REGPARM_MAX, + rtx ret = construct_container (TYPE_MODE (valtype), valtype, 1, + REGPARM_MAX, SSE_REGPARM_MAX, x86_64_int_return_registers, 0); - /* For zero sized structures, construct_container return NULL, but we - need to keep rest of compiler happy by returning meaningful value. */ + /* For zero sized structures, construct_container return NULL, but we need + to keep rest of compiler happy by returning meaningful value. */ if (!ret) ret = gen_rtx_REG (TYPE_MODE (valtype), 0); return ret; } else - { - tree fn = NULL_TREE, fntype; - if (fntype_or_decl - && DECL_P (fntype_or_decl)) - fn = fntype_or_decl; - fntype = fn ? TREE_TYPE (fn) : fntype_or_decl; - return gen_rtx_REG (TYPE_MODE (valtype), - ix86_value_regno (natmode, fn, fntype)); - } + return gen_rtx_REG (TYPE_MODE (valtype), + ix86_value_regno (TYPE_MODE (valtype))); } -/* Return true iff type is returned in memory. */ +/* Return false iff type is returned in memory. */ int ix86_return_in_memory (tree type) { int needed_intregs, needed_sseregs, size; - enum machine_mode mode = type_natural_mode (type); + enum machine_mode mode = TYPE_MODE (type); if (TARGET_64BIT) return !examine_argument (mode, type, 1, &needed_intregs, &needed_sseregs); @@ -3911,71 +2887,40 @@ ix86_return_in_memory (tree type) if (size < 8) return 0; - /* MMX/3dNow values are returned in MM0, - except when it doesn't exits. */ + /* MMX/3dNow values are returned on the stack, since we've + got to EMMS/FEMMS before returning. */ if (size == 8) - return (TARGET_MMX ? 0 : 1); + return 1; - /* SSE values are returned in XMM0, except when it doesn't exist. */ + /* SSE values are returned in XMM0. */ + /* ??? Except when it doesn't exist? We have a choice of + either (1) being abi incompatible with a -march switch, + or (2) generating an error here. Given no good solution, + I think the safest thing is one warning. The user won't + be able to use -Werror, but.... */ if (size == 16) - return (TARGET_SSE ? 0 : 1); - } - - if (mode == XFmode) - return 0; - - if (mode == TDmode) - return 1; - - if (size > 12) - return 1; - return 0; -} - -/* When returning SSE vector types, we have a choice of either - (1) being abi incompatible with a -march switch, or - (2) generating an error. - Given no good solution, I think the safest thing is one warning. - The user won't be able to use -Werror, but.... - - Choose the STRUCT_VALUE_RTX hook because that's (at present) only - called in response to actually generating a caller or callee that - uses such a type. As opposed to RETURN_IN_MEMORY, which is called - via aggregate_value_p for general type probing from tree-ssa. */ - -static rtx -ix86_struct_value_rtx (tree type, int incoming ATTRIBUTE_UNUSED) -{ - static bool warnedsse, warnedmmx; - - if (type) - { - /* Look at the return type of the function, not the function type. */ - enum machine_mode mode = TYPE_MODE (TREE_TYPE (type)); - - if (!TARGET_SSE && !warnedsse) { - if (mode == TImode - || (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 16)) - { - warnedsse = true; - warning (0, "SSE vector return without SSE enabled " - "changes the ABI"); - } - } + static bool warned; - if (!TARGET_MMX && !warnedmmx) - { - if (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 8) + if (TARGET_SSE) + return 0; + + if (!warned) { - warnedmmx = true; - warning (0, "MMX vector return without MMX enabled " + warned = true; + warning ("SSE vector return without SSE enabled " "changes the ABI"); } + return 1; } } - return NULL; + if (mode == XFmode) + return 0; + + if (size > 12) + return 1; + return 0; } /* Define how to find the value returned by a library function @@ -3991,14 +2936,11 @@ ix86_libcall_value (enum machine_mode mode) case SCmode: case DFmode: case DCmode: - case TFmode: - case SDmode: - case DDmode: - case TDmode: return gen_rtx_REG (mode, FIRST_SSE_REG); case XFmode: case XCmode: return gen_rtx_REG (mode, FIRST_FLOAT_REG); + case TFmode: case TCmode: return NULL; default: @@ -4006,48 +2948,23 @@ ix86_libcall_value (enum machine_mode mode) } } else - return gen_rtx_REG (mode, ix86_value_regno (mode, NULL, NULL)); + return gen_rtx_REG (mode, ix86_value_regno (mode)); } /* Given a mode, return the register to use for a return value. */ static int -ix86_value_regno (enum machine_mode mode, tree func, tree fntype) +ix86_value_regno (enum machine_mode mode) { - gcc_assert (!TARGET_64BIT); - - /* 8-byte vector modes in %mm0. See ix86_return_in_memory for where - we normally prevent this case when mmx is not available. However - some ABIs may require the result to be returned like DImode. */ - if (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 8) - return TARGET_MMX ? FIRST_MMX_REG : 0; - + /* Floating point return values in %st(0). */ + if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_FLOAT_RETURNS_IN_80387) + return FIRST_FLOAT_REG; /* 16-byte vector modes in %xmm0. See ix86_return_in_memory for where - we prevent this case when sse is not available. However some ABIs - may require the result to be returned like integer TImode. */ + we prevent this case when sse is not available. */ if (mode == TImode || (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 16)) - return TARGET_SSE ? FIRST_SSE_REG : 0; - - /* Decimal floating point values can go in %eax, unlike other float modes. */ - if (DECIMAL_FLOAT_MODE_P (mode)) - return 0; - - /* Most things go in %eax, except (unless -mno-fp-ret-in-387) fp values. */ - if (!SCALAR_FLOAT_MODE_P (mode) || !TARGET_FLOAT_RETURNS_IN_80387) - return 0; - - /* Floating point return values in %st(0), except for local functions when - SSE math is enabled or for functions with sseregparm attribute. */ - if ((func || fntype) - && (mode == SFmode || mode == DFmode)) - { - int sse_level = ix86_function_sseregparm (fntype, func); - if ((sse_level >= 1 && mode == SFmode) - || (sse_level == 2 && mode == DFmode)) - return FIRST_SSE_REG; - } - - return FIRST_FLOAT_REG; + return FIRST_SSE_REG; + /* Everything else in %eax. */ + return 0; } /* Create the va_list data type. */ @@ -4073,9 +2990,6 @@ ix86_build_builtin_va_list (void) f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"), ptr_type_node); - va_list_gpr_counter_field = f_gpr; - va_list_fpr_counter_field = f_fpr; - DECL_FIELD_CONTEXT (f_gpr) = record; DECL_FIELD_CONTEXT (f_fpr) = record; DECL_FIELD_CONTEXT (f_ovf) = record; @@ -4094,9 +3008,21 @@ ix86_build_builtin_va_list (void) return build_array_type (record, build_index_type (size_zero_node)); } -/* Worker function for TARGET_SETUP_INCOMING_VARARGS. */ +/* Perform any needed actions needed for a function that is receiving a + variable number of arguments. -static void + CUM is as above. + + MODE and TYPE are the mode and type of the current parameter. + + PRETEND_SIZE is a variable that should be set to the amount of stack + that must be pushed by the prolog to pretend that our caller pushed + it. + + Normally, this macro will push all remaining incoming registers on the + stack and set PRETEND_SIZE to the length of the registers pushed. */ + +void ix86_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int *pretend_size ATTRIBUTE_UNUSED, int no_rtl) @@ -4115,9 +3041,6 @@ ix86_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, if (!TARGET_64BIT) return; - if (! cfun->va_list_gpr_size && ! cfun->va_list_fpr_size) - return; - /* Indicate to allocate space on the stack for varargs save area. */ ix86_save_varrargs_registers = 1; @@ -4139,20 +3062,16 @@ ix86_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, set = get_varargs_alias_set (); - for (i = next_cum.regno; - i < ix86_regparm - && i < next_cum.regno + cfun->va_list_gpr_size / UNITS_PER_WORD; - i++) + for (i = next_cum.regno; i < ix86_regparm; i++) { mem = gen_rtx_MEM (Pmode, plus_constant (save_area, i * UNITS_PER_WORD)); - MEM_NOTRAP_P (mem) = 1; set_mem_alias_set (mem, set); emit_move_insn (mem, gen_rtx_REG (Pmode, x86_64_int_parameter_registers[i])); } - if (next_cum.sse_nregs && cfun->va_list_fpr_size) + if (next_cum.sse_nregs) { /* Now emit code to save SSE registers. The AX parameter contains number of SSE parameter registers used to call this function. We use @@ -4189,7 +3108,6 @@ ix86_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, plus_constant (save_area, 8 * REGPARM_MAX + 127))); mem = gen_rtx_MEM (BLKmode, plus_constant (tmp_reg, -127)); - MEM_NOTRAP_P (mem) = 1; set_mem_alias_set (mem, set); set_mem_align (mem, BITS_PER_WORD); @@ -4208,7 +3126,6 @@ ix86_va_start (tree valist, rtx nextarg) HOST_WIDE_INT words, n_gpr, n_fpr; tree f_gpr, f_fpr, f_ovf, f_sav; tree gpr, fpr, ovf, sav, t; - tree type; /* Only 64bit target needs something special. */ if (!TARGET_64BIT) @@ -4223,10 +3140,10 @@ ix86_va_start (tree valist, rtx nextarg) f_sav = TREE_CHAIN (f_ovf); valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist); - gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); - fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); - ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); - sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); + gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr); + fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr); + ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf); + sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav); /* Count number of gp and fp argument registers used. */ words = current_function_args_info.words; @@ -4237,106 +3154,96 @@ ix86_va_start (tree valist, rtx nextarg) fprintf (stderr, "va_start: words = %d, n_gpr = %d, n_fpr = %d\n", (int) words, (int) n_gpr, (int) n_fpr); - if (cfun->va_list_gpr_size) - { - type = TREE_TYPE (gpr); - t = build2 (MODIFY_EXPR, type, gpr, - build_int_cst (type, n_gpr * 8)); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } + t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, + build_int_2 (n_gpr * 8, 0)); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - if (cfun->va_list_fpr_size) - { - type = TREE_TYPE (fpr); - t = build2 (MODIFY_EXPR, type, fpr, - build_int_cst (type, n_fpr * 16 + 8*REGPARM_MAX)); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } + t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, + build_int_2 (n_fpr * 16 + 8*REGPARM_MAX, 0)); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); /* Find the overflow area. */ - type = TREE_TYPE (ovf); - t = make_tree (type, virtual_incoming_args_rtx); + t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx); if (words != 0) - t = build2 (PLUS_EXPR, type, t, - build_int_cst (type, words * UNITS_PER_WORD)); - t = build2 (MODIFY_EXPR, type, ovf, t); + t = build (PLUS_EXPR, TREE_TYPE (ovf), t, + build_int_2 (words * UNITS_PER_WORD, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - if (cfun->va_list_gpr_size || cfun->va_list_fpr_size) - { - /* Find the register save area. - Prologue of the function save it right above stack frame. */ - type = TREE_TYPE (sav); - t = make_tree (type, frame_pointer_rtx); - t = build2 (MODIFY_EXPR, type, sav, t); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } + /* Find the register save area. + Prologue of the function save it right above stack frame. */ + t = make_tree (TREE_TYPE (sav), frame_pointer_rtx); + t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } /* Implement va_arg. */ - -tree -ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) +rtx +ix86_va_arg (tree valist, tree type) { static const int intreg[6] = { 0, 1, 2, 3, 4, 5 }; tree f_gpr, f_fpr, f_ovf, f_sav; tree gpr, fpr, ovf, sav, t; int size, rsize; - tree lab_false, lab_over = NULL_TREE; - tree addr, t2; + rtx lab_false, lab_over = NULL_RTX; + rtx addr_rtx, r; rtx container; int indirect_p = 0; - tree ptrtype; - enum machine_mode nat_mode; /* Only 64bit target needs something special. */ if (!TARGET_64BIT) - return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); + { + return std_expand_builtin_va_arg (valist, type); + } f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); f_fpr = TREE_CHAIN (f_gpr); f_ovf = TREE_CHAIN (f_fpr); f_sav = TREE_CHAIN (f_ovf); - valist = build_va_arg_indirect_ref (valist); - gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); - fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); - ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); - sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); + valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist); + gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr); + fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr); + ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf); + sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav); - indirect_p = pass_by_reference (NULL, TYPE_MODE (type), type, false); - if (indirect_p) - type = build_pointer_type (type); size = int_size_in_bytes (type); + if (size == -1) + { + /* Passed by reference. */ + indirect_p = 1; + type = build_pointer_type (type); + size = int_size_in_bytes (type); + } rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; - nat_mode = type_natural_mode (type); - container = construct_container (nat_mode, TYPE_MODE (type), type, 0, + container = construct_container (TYPE_MODE (type), type, 0, REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0); + /* + * Pull the value out of the saved registers ... + */ - /* Pull the value out of the saved registers. */ - - addr = create_tmp_var (ptr_type_node, "addr"); - DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set (); + addr_rtx = gen_reg_rtx (Pmode); if (container) { + rtx int_addr_rtx, sse_addr_rtx; int needed_intregs, needed_sseregs; - bool need_temp; - tree int_addr, sse_addr; + int need_temp; - lab_false = create_artificial_label (); - lab_over = create_artificial_label (); + lab_over = gen_label_rtx (); + lab_false = gen_label_rtx (); - examine_argument (nat_mode, type, 0, &needed_intregs, &needed_sseregs); + examine_argument (TYPE_MODE (type), type, 0, + &needed_intregs, &needed_sseregs); - need_temp = (!REG_P (container) - && ((needed_intregs && TYPE_ALIGN (type) > 64) - || TYPE_ALIGN (type) > 128)); + + need_temp = ((needed_intregs && TYPE_ALIGN (type) > 64) + || TYPE_ALIGN (type) > 128); /* In case we are passing structure, verify that it is consecutive block on the register save area. If not we need to do moves. */ @@ -4370,161 +3277,230 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) } if (!need_temp) { - int_addr = addr; - sse_addr = addr; + int_addr_rtx = addr_rtx; + sse_addr_rtx = addr_rtx; } else { - int_addr = create_tmp_var (ptr_type_node, "int_addr"); - DECL_POINTER_ALIAS_SET (int_addr) = get_varargs_alias_set (); - sse_addr = create_tmp_var (ptr_type_node, "sse_addr"); - DECL_POINTER_ALIAS_SET (sse_addr) = get_varargs_alias_set (); + int_addr_rtx = gen_reg_rtx (Pmode); + sse_addr_rtx = gen_reg_rtx (Pmode); } - /* First ensure that we fit completely in registers. */ if (needed_intregs) { - t = build_int_cst (TREE_TYPE (gpr), - (REGPARM_MAX - needed_intregs + 1) * 8); - t = build2 (GE_EXPR, boolean_type_node, gpr, t); - t2 = build1 (GOTO_EXPR, void_type_node, lab_false); - t = build3 (COND_EXPR, void_type_node, t, t2, NULL_TREE); - gimplify_and_add (t, pre_p); + emit_cmp_and_jump_insns (expand_expr + (gpr, NULL_RTX, SImode, EXPAND_NORMAL), + GEN_INT ((REGPARM_MAX - needed_intregs + + 1) * 8), GE, const1_rtx, SImode, + 1, lab_false); } if (needed_sseregs) { - t = build_int_cst (TREE_TYPE (fpr), - (SSE_REGPARM_MAX - needed_sseregs + 1) * 16 - + REGPARM_MAX * 8); - t = build2 (GE_EXPR, boolean_type_node, fpr, t); - t2 = build1 (GOTO_EXPR, void_type_node, lab_false); - t = build3 (COND_EXPR, void_type_node, t, t2, NULL_TREE); - gimplify_and_add (t, pre_p); + emit_cmp_and_jump_insns (expand_expr + (fpr, NULL_RTX, SImode, EXPAND_NORMAL), + GEN_INT ((SSE_REGPARM_MAX - + needed_sseregs + 1) * 16 + + REGPARM_MAX * 8), GE, const1_rtx, + SImode, 1, lab_false); } /* Compute index to start of area used for integer regs. */ if (needed_intregs) { - /* int_addr = gpr + sav; */ - t = fold_convert (ptr_type_node, gpr); - t = build2 (PLUS_EXPR, ptr_type_node, sav, t); - t = build2 (MODIFY_EXPR, void_type_node, int_addr, t); - gimplify_and_add (t, pre_p); + t = build (PLUS_EXPR, ptr_type_node, sav, gpr); + r = expand_expr (t, int_addr_rtx, Pmode, EXPAND_NORMAL); + if (r != int_addr_rtx) + emit_move_insn (int_addr_rtx, r); } if (needed_sseregs) { - /* sse_addr = fpr + sav; */ - t = fold_convert (ptr_type_node, fpr); - t = build2 (PLUS_EXPR, ptr_type_node, sav, t); - t = build2 (MODIFY_EXPR, void_type_node, sse_addr, t); - gimplify_and_add (t, pre_p); + t = build (PLUS_EXPR, ptr_type_node, sav, fpr); + r = expand_expr (t, sse_addr_rtx, Pmode, EXPAND_NORMAL); + if (r != sse_addr_rtx) + emit_move_insn (sse_addr_rtx, r); } if (need_temp) { int i; - tree temp = create_tmp_var (type, "va_arg_tmp"); + rtx mem; + rtx x; - /* addr = &temp; */ - t = build1 (ADDR_EXPR, build_pointer_type (type), temp); - t = build2 (MODIFY_EXPR, void_type_node, addr, t); - gimplify_and_add (t, pre_p); + /* Never use the memory itself, as it has the alias set. */ + x = XEXP (assign_temp (type, 0, 1, 0), 0); + mem = gen_rtx_MEM (BLKmode, x); + force_operand (x, addr_rtx); + set_mem_alias_set (mem, get_varargs_alias_set ()); + set_mem_align (mem, BITS_PER_UNIT); for (i = 0; i < XVECLEN (container, 0); i++) { rtx slot = XVECEXP (container, 0, i); rtx reg = XEXP (slot, 0); enum machine_mode mode = GET_MODE (reg); - tree piece_type = lang_hooks.types.type_for_mode (mode, 1); - tree addr_type = build_pointer_type (piece_type); - tree src_addr, src; + rtx src_addr; + rtx src_mem; int src_offset; - tree dest_addr, dest; + rtx dest_mem; if (SSE_REGNO_P (REGNO (reg))) { - src_addr = sse_addr; + src_addr = sse_addr_rtx; src_offset = (REGNO (reg) - FIRST_SSE_REG) * 16; } else { - src_addr = int_addr; + src_addr = int_addr_rtx; src_offset = REGNO (reg) * 8; } - src_addr = fold_convert (addr_type, src_addr); - src_addr = fold (build2 (PLUS_EXPR, addr_type, src_addr, - size_int (src_offset))); - src = build_va_arg_indirect_ref (src_addr); - - dest_addr = fold_convert (addr_type, addr); - dest_addr = fold (build2 (PLUS_EXPR, addr_type, dest_addr, - size_int (INTVAL (XEXP (slot, 1))))); - dest = build_va_arg_indirect_ref (dest_addr); - - t = build2 (MODIFY_EXPR, void_type_node, dest, src); - gimplify_and_add (t, pre_p); + src_mem = gen_rtx_MEM (mode, src_addr); + set_mem_alias_set (src_mem, get_varargs_alias_set ()); + src_mem = adjust_address (src_mem, mode, src_offset); + dest_mem = adjust_address (mem, mode, INTVAL (XEXP (slot, 1))); + emit_move_insn (dest_mem, src_mem); } } if (needed_intregs) { - t = build2 (PLUS_EXPR, TREE_TYPE (gpr), gpr, - build_int_cst (TREE_TYPE (gpr), needed_intregs * 8)); - t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t); - gimplify_and_add (t, pre_p); + t = + build (PLUS_EXPR, TREE_TYPE (gpr), gpr, + build_int_2 (needed_intregs * 8, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } if (needed_sseregs) { - t = build2 (PLUS_EXPR, TREE_TYPE (fpr), fpr, - build_int_cst (TREE_TYPE (fpr), needed_sseregs * 16)); - t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t); - gimplify_and_add (t, pre_p); + t = + build (PLUS_EXPR, TREE_TYPE (fpr), fpr, + build_int_2 (needed_sseregs * 16, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } - t = build1 (GOTO_EXPR, void_type_node, lab_over); - gimplify_and_add (t, pre_p); - - t = build1 (LABEL_EXPR, void_type_node, lab_false); - append_to_statement_list (t, pre_p); + emit_jump_insn (gen_jump (lab_over)); + emit_barrier (); + emit_label (lab_false); } /* ... otherwise out of the overflow area. */ /* Care for on-stack alignment if needed. */ - if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64 - || integer_zerop (TYPE_SIZE (type))) + if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64) t = ovf; else { HOST_WIDE_INT align = FUNCTION_ARG_BOUNDARY (VOIDmode, type) / 8; - t = build2 (PLUS_EXPR, TREE_TYPE (ovf), ovf, - build_int_cst (TREE_TYPE (ovf), align - 1)); - t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t, - build_int_cst (TREE_TYPE (t), -align)); + t = build (PLUS_EXPR, TREE_TYPE (ovf), ovf, build_int_2 (align - 1, 0)); + t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1)); } - gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue); + t = save_expr (t); - t2 = build2 (MODIFY_EXPR, void_type_node, addr, t); - gimplify_and_add (t2, pre_p); + r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL); + if (r != addr_rtx) + emit_move_insn (addr_rtx, r); - t = build2 (PLUS_EXPR, TREE_TYPE (t), t, - build_int_cst (TREE_TYPE (t), rsize * UNITS_PER_WORD)); - t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); - gimplify_and_add (t, pre_p); + t = + build (PLUS_EXPR, TREE_TYPE (t), t, + build_int_2 (rsize * UNITS_PER_WORD, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); if (container) + emit_label (lab_over); + + if (indirect_p) { - t = build1 (LABEL_EXPR, void_type_node, lab_over); - append_to_statement_list (t, pre_p); + r = gen_rtx_MEM (Pmode, addr_rtx); + set_mem_alias_set (r, get_varargs_alias_set ()); + emit_move_insn (addr_rtx, r); } - ptrtype = build_pointer_type (type); - addr = fold_convert (ptrtype, addr); - - if (indirect_p) - addr = build_va_arg_indirect_ref (addr); - return build_va_arg_indirect_ref (addr); + return addr_rtx; } +/* Return nonzero if OP is either a i387 or SSE fp register. */ +int +any_fp_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return ANY_FP_REG_P (op); +} + +/* Return nonzero if OP is an i387 fp register. */ +int +fp_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return FP_REG_P (op); +} + +/* Return nonzero if OP is a non-fp register_operand. */ +int +register_and_not_any_fp_reg_operand (rtx op, enum machine_mode mode) +{ + return register_operand (op, mode) && !ANY_FP_REG_P (op); +} + +/* Return nonzero if OP is a register operand other than an + i387 fp register. */ +int +register_and_not_fp_reg_operand (rtx op, enum machine_mode mode) +{ + return register_operand (op, mode) && !FP_REG_P (op); +} + +/* Return nonzero if OP is general operand representable on x86_64. */ + +int +x86_64_general_operand (rtx op, enum machine_mode mode) +{ + if (!TARGET_64BIT) + return general_operand (op, mode); + if (nonimmediate_operand (op, mode)) + return 1; + return x86_64_sign_extended_value (op); +} + +/* Return nonzero if OP is general operand representable on x86_64 + as either sign extended or zero extended constant. */ + +int +x86_64_szext_general_operand (rtx op, enum machine_mode mode) +{ + if (!TARGET_64BIT) + return general_operand (op, mode); + if (nonimmediate_operand (op, mode)) + return 1; + return x86_64_sign_extended_value (op) || x86_64_zero_extended_value (op); +} + +/* Return nonzero if OP is nonmemory operand representable on x86_64. */ + +int +x86_64_nonmemory_operand (rtx op, enum machine_mode mode) +{ + if (!TARGET_64BIT) + return nonmemory_operand (op, mode); + if (register_operand (op, mode)) + return 1; + return x86_64_sign_extended_value (op); +} + +/* Return nonzero if OP is nonmemory operand acceptable by movabs patterns. */ + +int +x86_64_movabs_operand (rtx op, enum machine_mode mode) +{ + if (!TARGET_64BIT || !flag_pic) + return nonmemory_operand (op, mode); + if (register_operand (op, mode) || x86_64_sign_extended_value (op)) + return 1; + if (CONSTANT_P (op) && !symbolic_reference_mentioned_p (op)) + return 1; + return 0; +} + /* Return nonzero if OPNUM's MEM should be matched in movabs* patterns. */ @@ -4536,13 +3512,859 @@ ix86_check_movabs (rtx insn, int opnum) set = PATTERN (insn); if (GET_CODE (set) == PARALLEL) set = XVECEXP (set, 0, 0); - gcc_assert (GET_CODE (set) == SET); + if (GET_CODE (set) != SET) + abort (); mem = XEXP (set, opnum); while (GET_CODE (mem) == SUBREG) mem = SUBREG_REG (mem); - gcc_assert (GET_CODE (mem) == MEM); + if (GET_CODE (mem) != MEM) + abort (); return (volatile_ok || !MEM_VOLATILE_P (mem)); } + +/* Return nonzero if OP is nonmemory operand representable on x86_64. */ + +int +x86_64_szext_nonmemory_operand (rtx op, enum machine_mode mode) +{ + if (!TARGET_64BIT) + return nonmemory_operand (op, mode); + if (register_operand (op, mode)) + return 1; + return x86_64_sign_extended_value (op) || x86_64_zero_extended_value (op); +} + +/* Return nonzero if OP is immediate operand representable on x86_64. */ + +int +x86_64_immediate_operand (rtx op, enum machine_mode mode) +{ + if (!TARGET_64BIT) + return immediate_operand (op, mode); + return x86_64_sign_extended_value (op); +} + +/* Return nonzero if OP is immediate operand representable on x86_64. */ + +int +x86_64_zext_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return x86_64_zero_extended_value (op); +} + +/* Return nonzero if OP is CONST_INT >= 1 and <= 31 (a valid operand + for shift & compare patterns, as shifting by 0 does not change flags), + else return zero. */ + +int +const_int_1_31_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return (GET_CODE (op) == CONST_INT && INTVAL (op) >= 1 && INTVAL (op) <= 31); +} + +/* Returns 1 if OP is either a symbol reference or a sum of a symbol + reference and a constant. */ + +int +symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + switch (GET_CODE (op)) + { + case SYMBOL_REF: + case LABEL_REF: + return 1; + + case CONST: + op = XEXP (op, 0); + if (GET_CODE (op) == SYMBOL_REF + || GET_CODE (op) == LABEL_REF + || (GET_CODE (op) == UNSPEC + && (XINT (op, 1) == UNSPEC_GOT + || XINT (op, 1) == UNSPEC_GOTOFF + || XINT (op, 1) == UNSPEC_GOTPCREL))) + return 1; + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 1)) != CONST_INT) + return 0; + + op = XEXP (op, 0); + if (GET_CODE (op) == SYMBOL_REF + || GET_CODE (op) == LABEL_REF) + return 1; + /* Only @GOTOFF gets offsets. */ + if (GET_CODE (op) != UNSPEC + || XINT (op, 1) != UNSPEC_GOTOFF) + return 0; + + op = XVECEXP (op, 0, 0); + if (GET_CODE (op) == SYMBOL_REF + || GET_CODE (op) == LABEL_REF) + return 1; + return 0; + + default: + return 0; + } +} + +/* Return true if the operand contains a @GOT or @GOTOFF reference. */ + +int +pic_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + if (GET_CODE (op) != CONST) + return 0; + op = XEXP (op, 0); + if (TARGET_64BIT) + { + if (GET_CODE (op) == UNSPEC + && XINT (op, 1) == UNSPEC_GOTPCREL) + return 1; + if (GET_CODE (op) == PLUS + && GET_CODE (XEXP (op, 0)) == UNSPEC + && XINT (XEXP (op, 0), 1) == UNSPEC_GOTPCREL) + return 1; + } + else + { + if (GET_CODE (op) == UNSPEC) + return 1; + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 1)) != CONST_INT) + return 0; + op = XEXP (op, 0); + if (GET_CODE (op) == UNSPEC) + return 1; + } + return 0; +} + +/* Return true if OP is a symbolic operand that resolves locally. */ + +static int +local_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + if (GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == PLUS + && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) + op = XEXP (XEXP (op, 0), 0); + + if (GET_CODE (op) == LABEL_REF) + return 1; + + if (GET_CODE (op) != SYMBOL_REF) + return 0; + + if (SYMBOL_REF_LOCAL_P (op)) + return 1; + + /* There is, however, a not insubstantial body of code in the rest of + the compiler that assumes it can just stick the results of + ASM_GENERATE_INTERNAL_LABEL in a symbol_ref and have done. */ + /* ??? This is a hack. Should update the body of the compiler to + always create a DECL an invoke targetm.encode_section_info. */ + if (strncmp (XSTR (op, 0), internal_label_prefix, + internal_label_prefix_len) == 0) + return 1; + + return 0; +} + +/* Test for various thread-local symbols. */ + +int +tls_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + if (GET_CODE (op) != SYMBOL_REF) + return 0; + return SYMBOL_REF_TLS_MODEL (op); +} + +static inline int +tls_symbolic_operand_1 (rtx op, enum tls_model kind) +{ + if (GET_CODE (op) != SYMBOL_REF) + return 0; + return SYMBOL_REF_TLS_MODEL (op) == kind; +} + +int +global_dynamic_symbolic_operand (rtx op, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return tls_symbolic_operand_1 (op, TLS_MODEL_GLOBAL_DYNAMIC); +} + +int +local_dynamic_symbolic_operand (rtx op, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return tls_symbolic_operand_1 (op, TLS_MODEL_LOCAL_DYNAMIC); +} + +int +initial_exec_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return tls_symbolic_operand_1 (op, TLS_MODEL_INITIAL_EXEC); +} + +int +local_exec_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return tls_symbolic_operand_1 (op, TLS_MODEL_LOCAL_EXEC); +} + +/* Test for a valid operand for a call instruction. Don't allow the + arg pointer register or virtual regs since they may decay into + reg + const, which the patterns can't handle. */ + +int +call_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + /* Disallow indirect through a virtual register. This leads to + compiler aborts when trying to eliminate them. */ + if (GET_CODE (op) == REG + && (op == arg_pointer_rtx + || op == frame_pointer_rtx + || (REGNO (op) >= FIRST_PSEUDO_REGISTER + && REGNO (op) <= LAST_VIRTUAL_REGISTER))) + return 0; + + /* Disallow `call 1234'. Due to varying assembler lameness this + gets either rejected or translated to `call .+1234'. */ + if (GET_CODE (op) == CONST_INT) + return 0; + + /* Explicitly allow SYMBOL_REF even if pic. */ + if (GET_CODE (op) == SYMBOL_REF) + return 1; + + /* Otherwise we can allow any general_operand in the address. */ + return general_operand (op, Pmode); +} + +/* Test for a valid operand for a call instruction. Don't allow the + arg pointer register or virtual regs since they may decay into + reg + const, which the patterns can't handle. */ + +int +sibcall_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + /* Disallow indirect through a virtual register. This leads to + compiler aborts when trying to eliminate them. */ + if (GET_CODE (op) == REG + && (op == arg_pointer_rtx + || op == frame_pointer_rtx + || (REGNO (op) >= FIRST_PSEUDO_REGISTER + && REGNO (op) <= LAST_VIRTUAL_REGISTER))) + return 0; + + /* Explicitly allow SYMBOL_REF even if pic. */ + if (GET_CODE (op) == SYMBOL_REF) + return 1; + + /* Otherwise we can only allow register operands. */ + return register_operand (op, Pmode); +} + +int +constant_call_address_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + if (GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == PLUS + && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) + op = XEXP (XEXP (op, 0), 0); + return GET_CODE (op) == SYMBOL_REF; +} + +/* Match exactly zero and one. */ + +int +const0_operand (rtx op, enum machine_mode mode) +{ + return op == CONST0_RTX (mode); +} + +int +const1_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return op == const1_rtx; +} + +/* Match 2, 4, or 8. Used for leal multiplicands. */ + +int +const248_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return (GET_CODE (op) == CONST_INT + && (INTVAL (op) == 2 || INTVAL (op) == 4 || INTVAL (op) == 8)); +} + +int +const_0_to_3_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return (GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 4); +} + +int +const_0_to_7_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return (GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 8); +} + +int +const_0_to_15_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return (GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 16); +} + +int +const_0_to_255_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return (GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 256); +} + + +/* True if this is a constant appropriate for an increment or decrement. */ + +int +incdec_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + /* On Pentium4, the inc and dec operations causes extra dependency on flag + registers, since carry flag is not set. */ + if (TARGET_PENTIUM4 && !optimize_size) + return 0; + return op == const1_rtx || op == constm1_rtx; +} + +/* Return nonzero if OP is acceptable as operand of DImode shift + expander. */ + +int +shiftdi_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + if (TARGET_64BIT) + return nonimmediate_operand (op, mode); + else + return register_operand (op, mode); +} + +/* Return false if this is the stack pointer, or any other fake + register eliminable to the stack pointer. Otherwise, this is + a register operand. + + This is used to prevent esp from being used as an index reg. + Which would only happen in pathological cases. */ + +int +reg_no_sp_operand (rtx op, enum machine_mode mode) +{ + rtx t = op; + if (GET_CODE (t) == SUBREG) + t = SUBREG_REG (t); + if (t == stack_pointer_rtx || t == arg_pointer_rtx || t == frame_pointer_rtx) + return 0; + + return register_operand (op, mode); +} + +int +mmx_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return MMX_REG_P (op); +} + +/* Return false if this is any eliminable register. Otherwise + general_operand. */ + +int +general_no_elim_operand (rtx op, enum machine_mode mode) +{ + rtx t = op; + if (GET_CODE (t) == SUBREG) + t = SUBREG_REG (t); + if (t == arg_pointer_rtx || t == frame_pointer_rtx + || t == virtual_incoming_args_rtx || t == virtual_stack_vars_rtx + || t == virtual_stack_dynamic_rtx) + return 0; + if (REG_P (t) + && REGNO (t) >= FIRST_VIRTUAL_REGISTER + && REGNO (t) <= LAST_VIRTUAL_REGISTER) + return 0; + + return general_operand (op, mode); +} + +/* Return false if this is any eliminable register. Otherwise + register_operand or const_int. */ + +int +nonmemory_no_elim_operand (rtx op, enum machine_mode mode) +{ + rtx t = op; + if (GET_CODE (t) == SUBREG) + t = SUBREG_REG (t); + if (t == arg_pointer_rtx || t == frame_pointer_rtx + || t == virtual_incoming_args_rtx || t == virtual_stack_vars_rtx + || t == virtual_stack_dynamic_rtx) + return 0; + + return GET_CODE (op) == CONST_INT || register_operand (op, mode); +} + +/* Return false if this is any eliminable register or stack register, + otherwise work like register_operand. */ + +int +index_register_operand (rtx op, enum machine_mode mode) +{ + rtx t = op; + if (GET_CODE (t) == SUBREG) + t = SUBREG_REG (t); + if (!REG_P (t)) + return 0; + if (t == arg_pointer_rtx + || t == frame_pointer_rtx + || t == virtual_incoming_args_rtx + || t == virtual_stack_vars_rtx + || t == virtual_stack_dynamic_rtx + || REGNO (t) == STACK_POINTER_REGNUM) + return 0; + + return general_operand (op, mode); +} + +/* Return true if op is a Q_REGS class register. */ + +int +q_regs_operand (rtx op, enum machine_mode mode) +{ + if (mode != VOIDmode && GET_MODE (op) != mode) + return 0; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + return ANY_QI_REG_P (op); +} + +/* Return true if op is an flags register. */ + +int +flags_reg_operand (rtx op, enum machine_mode mode) +{ + if (mode != VOIDmode && GET_MODE (op) != mode) + return 0; + return REG_P (op) && REGNO (op) == FLAGS_REG && GET_MODE (op) != VOIDmode; +} + +/* Return true if op is a NON_Q_REGS class register. */ + +int +non_q_regs_operand (rtx op, enum machine_mode mode) +{ + if (mode != VOIDmode && GET_MODE (op) != mode) + return 0; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + return NON_QI_REG_P (op); +} + +int +zero_extended_scalar_load_operand (rtx op, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + unsigned n_elts; + if (GET_CODE (op) != MEM) + return 0; + op = maybe_get_pool_constant (op); + if (!op) + return 0; + if (GET_CODE (op) != CONST_VECTOR) + return 0; + n_elts = + (GET_MODE_SIZE (GET_MODE (op)) / + GET_MODE_SIZE (GET_MODE_INNER (GET_MODE (op)))); + for (n_elts--; n_elts > 0; n_elts--) + { + rtx elt = CONST_VECTOR_ELT (op, n_elts); + if (elt != CONST0_RTX (GET_MODE_INNER (GET_MODE (op)))) + return 0; + } + return 1; +} + +/* Return 1 when OP is operand acceptable for standard SSE move. */ +int +vector_move_operand (rtx op, enum machine_mode mode) +{ + if (nonimmediate_operand (op, mode)) + return 1; + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + return (op == CONST0_RTX (GET_MODE (op))); +} + +/* Return true if op if a valid address, and does not contain + a segment override. */ + +int +no_seg_address_operand (rtx op, enum machine_mode mode) +{ + struct ix86_address parts; + + if (! address_operand (op, mode)) + return 0; + + if (! ix86_decompose_address (op, &parts)) + abort (); + + return parts.seg == SEG_DEFAULT; +} + +/* Return 1 if OP is a comparison that can be used in the CMPSS/CMPPS + insns. */ +int +sse_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + enum rtx_code code = GET_CODE (op); + switch (code) + { + /* Operations supported directly. */ + case EQ: + case LT: + case LE: + case UNORDERED: + case NE: + case UNGE: + case UNGT: + case ORDERED: + return 1; + /* These are equivalent to ones above in non-IEEE comparisons. */ + case UNEQ: + case UNLT: + case UNLE: + case LTGT: + case GE: + case GT: + return !TARGET_IEEE_FP; + default: + return 0; + } +} +/* Return 1 if OP is a valid comparison operator in valid mode. */ +int +ix86_comparison_operator (rtx op, enum machine_mode mode) +{ + enum machine_mode inmode; + enum rtx_code code = GET_CODE (op); + if (mode != VOIDmode && GET_MODE (op) != mode) + return 0; + if (GET_RTX_CLASS (code) != '<') + return 0; + inmode = GET_MODE (XEXP (op, 0)); + + if (inmode == CCFPmode || inmode == CCFPUmode) + { + enum rtx_code second_code, bypass_code; + ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code); + return (bypass_code == NIL && second_code == NIL); + } + switch (code) + { + case EQ: case NE: + return 1; + case LT: case GE: + if (inmode == CCmode || inmode == CCGCmode + || inmode == CCGOCmode || inmode == CCNOmode) + return 1; + return 0; + case LTU: case GTU: case LEU: case ORDERED: case UNORDERED: case GEU: + if (inmode == CCmode) + return 1; + return 0; + case GT: case LE: + if (inmode == CCmode || inmode == CCGCmode || inmode == CCNOmode) + return 1; + return 0; + default: + return 0; + } +} + +/* Return 1 if OP is a valid comparison operator testing carry flag + to be set. */ +int +ix86_carry_flag_operator (rtx op, enum machine_mode mode) +{ + enum machine_mode inmode; + enum rtx_code code = GET_CODE (op); + + if (mode != VOIDmode && GET_MODE (op) != mode) + return 0; + if (GET_RTX_CLASS (code) != '<') + return 0; + inmode = GET_MODE (XEXP (op, 0)); + if (GET_CODE (XEXP (op, 0)) != REG + || REGNO (XEXP (op, 0)) != 17 + || XEXP (op, 1) != const0_rtx) + return 0; + + if (inmode == CCFPmode || inmode == CCFPUmode) + { + enum rtx_code second_code, bypass_code; + + ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code); + if (bypass_code != NIL || second_code != NIL) + return 0; + code = ix86_fp_compare_code_to_integer (code); + } + else if (inmode != CCmode) + return 0; + return code == LTU; +} + +/* Return 1 if OP is a comparison operator that can be issued by fcmov. */ + +int +fcmov_comparison_operator (rtx op, enum machine_mode mode) +{ + enum machine_mode inmode; + enum rtx_code code = GET_CODE (op); + + if (mode != VOIDmode && GET_MODE (op) != mode) + return 0; + if (GET_RTX_CLASS (code) != '<') + return 0; + inmode = GET_MODE (XEXP (op, 0)); + if (inmode == CCFPmode || inmode == CCFPUmode) + { + enum rtx_code second_code, bypass_code; + + ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code); + if (bypass_code != NIL || second_code != NIL) + return 0; + code = ix86_fp_compare_code_to_integer (code); + } + /* i387 supports just limited amount of conditional codes. */ + switch (code) + { + case LTU: case GTU: case LEU: case GEU: + if (inmode == CCmode || inmode == CCFPmode || inmode == CCFPUmode) + return 1; + return 0; + case ORDERED: case UNORDERED: + case EQ: case NE: + return 1; + default: + return 0; + } +} + +/* Return 1 if OP is a binary operator that can be promoted to wider mode. */ + +int +promotable_binary_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + switch (GET_CODE (op)) + { + case MULT: + /* Modern CPUs have same latency for HImode and SImode multiply, + but 386 and 486 do HImode multiply faster. */ + return ix86_tune > PROCESSOR_I486; + case PLUS: + case AND: + case IOR: + case XOR: + case ASHIFT: + return 1; + default: + return 0; + } +} + +/* Nearly general operand, but accept any const_double, since we wish + to be able to drop them into memory rather than have them get pulled + into registers. */ + +int +cmp_fp_expander_operand (rtx op, enum machine_mode mode) +{ + if (mode != VOIDmode && mode != GET_MODE (op)) + return 0; + if (GET_CODE (op) == CONST_DOUBLE) + return 1; + return general_operand (op, mode); +} + +/* Match an SI or HImode register for a zero_extract. */ + +int +ext_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + int regno; + if ((!TARGET_64BIT || GET_MODE (op) != DImode) + && GET_MODE (op) != SImode && GET_MODE (op) != HImode) + return 0; + + if (!register_operand (op, VOIDmode)) + return 0; + + /* Be careful to accept only registers having upper parts. */ + regno = REG_P (op) ? REGNO (op) : REGNO (SUBREG_REG (op)); + return (regno > LAST_VIRTUAL_REGISTER || regno < 4); +} + +/* Return 1 if this is a valid binary floating-point operation. + OP is the expression matched, and MODE is its mode. */ + +int +binary_fp_operator (rtx op, enum machine_mode mode) +{ + if (mode != VOIDmode && mode != GET_MODE (op)) + return 0; + + switch (GET_CODE (op)) + { + case PLUS: + case MINUS: + case MULT: + case DIV: + return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT; + + default: + return 0; + } +} + +int +mult_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return GET_CODE (op) == MULT; +} + +int +div_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return GET_CODE (op) == DIV; +} + +int +arith_or_logical_operator (rtx op, enum machine_mode mode) +{ + return ((mode == VOIDmode || GET_MODE (op) == mode) + && (GET_RTX_CLASS (GET_CODE (op)) == 'c' + || GET_RTX_CLASS (GET_CODE (op)) == '2')); +} + +/* Returns 1 if OP is memory operand with a displacement. */ + +int +memory_displacement_operand (rtx op, enum machine_mode mode) +{ + struct ix86_address parts; + + if (! memory_operand (op, mode)) + return 0; + + if (! ix86_decompose_address (XEXP (op, 0), &parts)) + abort (); + + return parts.disp != NULL_RTX; +} + +/* To avoid problems when jump re-emits comparisons like testqi_ext_ccno_0, + re-recognize the operand to avoid a copy_to_mode_reg that will fail. + + ??? It seems likely that this will only work because cmpsi is an + expander, and no actual insns use this. */ + +int +cmpsi_operand (rtx op, enum machine_mode mode) +{ + if (nonimmediate_operand (op, mode)) + return 1; + + if (GET_CODE (op) == AND + && GET_MODE (op) == SImode + && GET_CODE (XEXP (op, 0)) == ZERO_EXTRACT + && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT + && GET_CODE (XEXP (XEXP (op, 0), 2)) == CONST_INT + && INTVAL (XEXP (XEXP (op, 0), 1)) == 8 + && INTVAL (XEXP (XEXP (op, 0), 2)) == 8 + && GET_CODE (XEXP (op, 1)) == CONST_INT) + return 1; + + return 0; +} + +/* Returns 1 if OP is memory operand that can not be represented by the + modRM array. */ + +int +long_memory_operand (rtx op, enum machine_mode mode) +{ + if (! memory_operand (op, mode)) + return 0; + + return memory_address_length (op) != 0; +} + +/* Return nonzero if the rtx is known aligned. */ + +int +aligned_operand (rtx op, enum machine_mode mode) +{ + struct ix86_address parts; + + if (!general_operand (op, mode)) + return 0; + + /* Registers and immediate operands are always "aligned". */ + if (GET_CODE (op) != MEM) + return 1; + + /* Don't even try to do any aligned optimizations with volatiles. */ + if (MEM_VOLATILE_P (op)) + return 0; + + op = XEXP (op, 0); + + /* Pushes and pops are only valid on the stack pointer. */ + if (GET_CODE (op) == PRE_DEC + || GET_CODE (op) == POST_INC) + return 1; + + /* Decode the address. */ + if (! ix86_decompose_address (op, &parts)) + abort (); + + /* Look for some component that isn't known to be aligned. */ + if (parts.index) + { + if (parts.scale < 4 + && REGNO_POINTER_ALIGN (REGNO (parts.index)) < 32) + return 0; + } + if (parts.base) + { + if (REGNO_POINTER_ALIGN (REGNO (parts.base)) < 32) + return 0; + } + if (parts.disp) + { + if (GET_CODE (parts.disp) != CONST_INT + || (INTVAL (parts.disp) & 3) != 0) + return 0; + } + + /* Didn't find one -- this must be an aligned address. */ + return 1; +} + +int +compare_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return GET_CODE (op) == COMPARE; +} /* Initialize the table of extra 80387 mathematical constants. */ @@ -4584,10 +4406,10 @@ standard_80387_constant_p (rtx x) if (x == CONST1_RTX (GET_MODE (x))) return 2; - /* For XFmode constants, try to find a special 80387 instruction when - optimizing for size or on those CPUs that benefit from them. */ + /* For XFmode constants, try to find a special 80387 instruction on + those CPUs that benefit from them. */ if (GET_MODE (x) == XFmode - && (optimize_size || x86_ext_80387_constants & TUNEMASK)) + && x86_ext_80387_constants & TUNEMASK) { REAL_VALUE_TYPE r; int i; @@ -4626,9 +4448,8 @@ standard_80387_constant_opcode (rtx x) return "fldl2t"; case 7: return "fldpi"; - default: - gcc_unreachable (); } + abort (); } /* Return the CONST_DOUBLE representing the 80387 constant that is @@ -4654,67 +4475,21 @@ standard_80387_constant_rtx (int idx) break; default: - gcc_unreachable (); + abort (); } return CONST_DOUBLE_FROM_REAL_VALUE (ext_80387_constants_table[i], XFmode); } -/* Return 1 if mode is a valid mode for sse. */ -static int -standard_sse_mode_p (enum machine_mode mode) -{ - switch (mode) - { - case V16QImode: - case V8HImode: - case V4SImode: - case V2DImode: - case V4SFmode: - case V2DFmode: - return 1; - - default: - return 0; - } -} - /* Return 1 if X is FP constant we can load to SSE register w/o using memory. */ int standard_sse_constant_p (rtx x) { - enum machine_mode mode = GET_MODE (x); - - if (x == const0_rtx || x == CONST0_RTX (GET_MODE (x))) + if (x == const0_rtx) return 1; - if (vector_all_ones_operand (x, mode) - && standard_sse_mode_p (mode)) - return TARGET_SSE2 ? 2 : -1; - - return 0; -} - -/* Return the opcode of the special instruction to be used to load - the constant X. */ - -const char * -standard_sse_constant_opcode (rtx insn, rtx x) -{ - switch (standard_sse_constant_p (x)) - { - case 1: - if (get_attr_mode (insn) == MODE_V4SF) - return "xorps\t%0, %0"; - else if (get_attr_mode (insn) == MODE_V2DF) - return "xorpd\t%0, %0"; - else - return "pxor\t%0, %0"; - case 2: - return "pcmpeqd\t%0, %0"; - } - gcc_unreachable (); + return (x == CONST0_RTX (GET_MODE (x))); } /* Returns 1 if OP contains a symbol reference */ @@ -4751,13 +4526,24 @@ symbolic_reference_mentioned_p (rtx op) body of a function. Do this only if the epilogue is simple, needing a couple of insns. Prior to reloading, we can't tell how many registers must be saved, so return 0 then. Return 0 if there is no frame - marker to de-allocate. */ + marker to de-allocate. + + If NON_SAVING_SETJMP is defined and true, then it is not possible + for the epilogue to be simple, so return 0. This is a special case + since NON_SAVING_SETJMP will not cause regs_ever_live to change + until final, but jump_optimize may need to know sooner if a + `return' is OK. */ int ix86_can_use_return_insn_p (void) { struct ix86_frame frame; +#ifdef NON_SAVING_SETJMP + if (NON_SAVING_SETJMP && current_function_calls_setjmp) + return 0; +#endif + if (! reload_completed || frame_pointer_needed) return 0; @@ -4771,6 +4557,196 @@ ix86_can_use_return_insn_p (void) return frame.to_allocate == 0 && frame.nregs == 0; } +/* Return 1 if VALUE can be stored in the sign extended immediate field. */ +int +x86_64_sign_extended_value (rtx value) +{ + switch (GET_CODE (value)) + { + /* CONST_DOUBLES never match, since HOST_BITS_PER_WIDE_INT is known + to be at least 32 and this all acceptable constants are + represented as CONST_INT. */ + case CONST_INT: + if (HOST_BITS_PER_WIDE_INT == 32) + return 1; + else + { + HOST_WIDE_INT val = trunc_int_for_mode (INTVAL (value), DImode); + return trunc_int_for_mode (val, SImode) == val; + } + break; + + /* For certain code models, the symbolic references are known to fit. + in CM_SMALL_PIC model we know it fits if it is local to the shared + library. Don't count TLS SYMBOL_REFs here, since they should fit + only if inside of UNSPEC handled below. */ + case SYMBOL_REF: + /* TLS symbols are not constant. */ + if (tls_symbolic_operand (value, Pmode)) + return false; + return (ix86_cmodel == CM_SMALL || ix86_cmodel == CM_KERNEL); + + /* For certain code models, the code is near as well. */ + case LABEL_REF: + return (ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM + || ix86_cmodel == CM_KERNEL); + + /* We also may accept the offsetted memory references in certain special + cases. */ + case CONST: + if (GET_CODE (XEXP (value, 0)) == UNSPEC) + switch (XINT (XEXP (value, 0), 1)) + { + case UNSPEC_GOTPCREL: + case UNSPEC_DTPOFF: + case UNSPEC_GOTNTPOFF: + case UNSPEC_NTPOFF: + return 1; + default: + break; + } + if (GET_CODE (XEXP (value, 0)) == PLUS) + { + rtx op1 = XEXP (XEXP (value, 0), 0); + rtx op2 = XEXP (XEXP (value, 0), 1); + HOST_WIDE_INT offset; + + if (ix86_cmodel == CM_LARGE) + return 0; + if (GET_CODE (op2) != CONST_INT) + return 0; + offset = trunc_int_for_mode (INTVAL (op2), DImode); + switch (GET_CODE (op1)) + { + case SYMBOL_REF: + /* For CM_SMALL assume that latest object is 16MB before + end of 31bits boundary. We may also accept pretty + large negative constants knowing that all objects are + in the positive half of address space. */ + if (ix86_cmodel == CM_SMALL + && offset < 16*1024*1024 + && trunc_int_for_mode (offset, SImode) == offset) + return 1; + /* For CM_KERNEL we know that all object resist in the + negative half of 32bits address space. We may not + accept negative offsets, since they may be just off + and we may accept pretty large positive ones. */ + if (ix86_cmodel == CM_KERNEL + && offset > 0 + && trunc_int_for_mode (offset, SImode) == offset) + return 1; + break; + case LABEL_REF: + /* These conditions are similar to SYMBOL_REF ones, just the + constraints for code models differ. */ + if ((ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM) + && offset < 16*1024*1024 + && trunc_int_for_mode (offset, SImode) == offset) + return 1; + if (ix86_cmodel == CM_KERNEL + && offset > 0 + && trunc_int_for_mode (offset, SImode) == offset) + return 1; + break; + case UNSPEC: + switch (XINT (op1, 1)) + { + case UNSPEC_DTPOFF: + case UNSPEC_NTPOFF: + if (offset > 0 + && trunc_int_for_mode (offset, SImode) == offset) + return 1; + } + break; + default: + return 0; + } + } + return 0; + default: + return 0; + } +} + +/* Return 1 if VALUE can be stored in the zero extended immediate field. */ +int +x86_64_zero_extended_value (rtx value) +{ + switch (GET_CODE (value)) + { + case CONST_DOUBLE: + if (HOST_BITS_PER_WIDE_INT == 32) + return (GET_MODE (value) == VOIDmode + && !CONST_DOUBLE_HIGH (value)); + else + return 0; + case CONST_INT: + if (HOST_BITS_PER_WIDE_INT == 32) + return INTVAL (value) >= 0; + else + return !(INTVAL (value) & ~(HOST_WIDE_INT) 0xffffffff); + break; + + /* For certain code models, the symbolic references are known to fit. */ + case SYMBOL_REF: + /* TLS symbols are not constant. */ + if (tls_symbolic_operand (value, Pmode)) + return false; + return ix86_cmodel == CM_SMALL; + + /* For certain code models, the code is near as well. */ + case LABEL_REF: + return ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM; + + /* We also may accept the offsetted memory references in certain special + cases. */ + case CONST: + if (GET_CODE (XEXP (value, 0)) == PLUS) + { + rtx op1 = XEXP (XEXP (value, 0), 0); + rtx op2 = XEXP (XEXP (value, 0), 1); + + if (ix86_cmodel == CM_LARGE) + return 0; + switch (GET_CODE (op1)) + { + case SYMBOL_REF: + return 0; + /* For small code model we may accept pretty large positive + offsets, since one bit is available for free. Negative + offsets are limited by the size of NULL pointer area + specified by the ABI. */ + if (ix86_cmodel == CM_SMALL + && GET_CODE (op2) == CONST_INT + && trunc_int_for_mode (INTVAL (op2), DImode) > -0x10000 + && (trunc_int_for_mode (INTVAL (op2), SImode) + == INTVAL (op2))) + return 1; + /* ??? For the kernel, we may accept adjustment of + -0x10000000, since we know that it will just convert + negative address space to positive, but perhaps this + is not worthwhile. */ + break; + case LABEL_REF: + /* These conditions are similar to SYMBOL_REF ones, just the + constraints for code models differ. */ + if ((ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM) + && GET_CODE (op2) == CONST_INT + && trunc_int_for_mode (INTVAL (op2), DImode) > -0x10000 + && (trunc_int_for_mode (INTVAL (op2), SImode) + == INTVAL (op2))) + return 1; + break; + default: + return 0; + } + } + return 0; + default: + return 0; + } +} + /* Value should be nonzero if functions must have frame pointers. Zero means the frame pointer need not be set up (and parms may be accessed via the stack pointer) in functions that seem suitable. */ @@ -4792,8 +4768,7 @@ ix86_frame_pointer_required (void) the frame pointer by default. Turn it back on now if we've not got a leaf function. */ if (TARGET_OMIT_LEAF_FRAME_POINTER - && (!current_function_is_leaf - || ix86_current_function_calls_tls_descriptor)) + && (!current_function_is_leaf)) return 1; if (current_function_profile) @@ -4810,7 +4785,7 @@ ix86_setup_frame_addresses (void) cfun->machine->accesses_prev_frame = 1; } -#if (defined(HAVE_GAS_HIDDEN) && (SUPPORTS_ONE_ONLY - 0)) || TARGET_MACHO +#if defined(HAVE_GAS_HIDDEN) && defined(SUPPORTS_ONE_ONLY) # define USE_HIDDEN_LINKONCE 1 #else # define USE_HIDDEN_LINKONCE 0 @@ -4824,8 +4799,6 @@ static int pic_labels_used; static void get_pc_thunk_name (char name[32], unsigned int regno) { - gcc_assert (!TARGET_64BIT); - if (USE_HIDDEN_LINKONCE) sprintf (name, "__i686.get_pc_thunk.%s", reg_names[regno]); else @@ -4851,19 +4824,6 @@ ix86_file_end (void) get_pc_thunk_name (name, regno); -#if TARGET_MACHO - if (TARGET_MACHO) - { - switch_to_section (darwin_sections[text_coal_section]); - fputs ("\t.weak_definition\t", asm_out_file); - assemble_name (asm_out_file, name); - fputs ("\n\t.private_extern\t", asm_out_file); - assemble_name (asm_out_file, name); - fputs ("\n", asm_out_file); - ASM_OUTPUT_LABEL (asm_out_file, name); - } - else -#endif if (USE_HIDDEN_LINKONCE) { tree decl; @@ -4875,7 +4835,7 @@ ix86_file_end (void) DECL_ONE_ONLY (decl) = 1; (*targetm.asm_out.unique_section) (decl, 0); - switch_to_section (get_named_section (decl, NULL, 0)); + named_section (decl, NULL, 0); (*targetm.asm_out.globalize_label) (asm_out_file, name); fputs ("\t.hidden\t", asm_out_file); @@ -4885,7 +4845,7 @@ ix86_file_end (void) } else { - switch_to_section (text_section); + text_section (); ASM_OUTPUT_LABEL (asm_out_file, name); } @@ -4902,7 +4862,7 @@ ix86_file_end (void) /* Emit code for the SET_GOT patterns. */ const char * -output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED) +output_set_got (rtx dest) { rtx xops[3]; @@ -4911,7 +4871,7 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED) if (! TARGET_DEEP_BRANCH_PREDICTION || !flag_pic) { - xops[2] = gen_rtx_LABEL_REF (Pmode, label ? label : gen_label_rtx ()); + xops[2] = gen_rtx_LABEL_REF (Pmode, gen_label_rtx ()); if (!flag_pic) output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops); @@ -4919,12 +4879,10 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED) output_asm_insn ("call\t%a2", xops); #if TARGET_MACHO - /* Output the Mach-O "canonical" label name ("Lxx$pb") here too. This - is what will be referenced by the Mach-O PIC subsystem. */ - if (!label) - ASM_OUTPUT_LABEL (asm_out_file, machopic_function_base_name ()); + /* Output the "canonical" label name ("Lxx$pb") here too. This + is what will be referred to by the Mach-O PIC subsystem. */ + ASM_OUTPUT_LABEL (asm_out_file, machopic_function_base_name ()); #endif - (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (XEXP (xops[2], 0))); @@ -4940,23 +4898,11 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED) xops[2] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); xops[2] = gen_rtx_MEM (QImode, xops[2]); output_asm_insn ("call\t%X2", xops); - /* Output the Mach-O "canonical" label name ("Lxx$pb") here too. This - is what will be referenced by the Mach-O PIC subsystem. */ -#if TARGET_MACHO - if (!label) - ASM_OUTPUT_LABEL (asm_out_file, machopic_function_base_name ()); - else - targetm.asm_out.internal_label (asm_out_file, "L", - CODE_LABEL_NUMBER (label)); -#endif } - if (TARGET_MACHO) - return ""; - if (!flag_pic || TARGET_DEEP_BRANCH_PREDICTION) output_asm_insn ("add{l}\t{%1, %0|%0, %1}", xops); - else + else if (!TARGET_MACHO) output_asm_insn ("add{l}\t{%1+[.-%a2], %0|%0, %1+(.-%a2)}", xops); return ""; @@ -4980,8 +4926,7 @@ gen_push (rtx arg) static unsigned int ix86_select_alt_pic_regnum (void) { - if (current_function_is_leaf && !current_function_profile - && !ix86_current_function_calls_tls_descriptor) + if (current_function_is_leaf && !current_function_profile) { int i; for (i = 2; i >= 0; --i) @@ -5021,10 +4966,6 @@ ix86_save_reg (unsigned int regno, int maybe_eh_return) } } - if (cfun->machine->force_align_arg_pointer - && regno == REGNO (cfun->machine->force_align_arg_pointer)) - return 1; - return (regs_ever_live[regno] && !call_used_regs[regno] && !fixed_regs[regno] @@ -5061,13 +5002,14 @@ ix86_initial_elimination_offset (int from, int to) return frame.hard_frame_pointer_offset - frame.frame_pointer_offset; else { - gcc_assert (to == STACK_POINTER_REGNUM); - - if (from == ARG_POINTER_REGNUM) + if (to != STACK_POINTER_REGNUM) + abort (); + else if (from == ARG_POINTER_REGNUM) return frame.stack_pointer_offset; - - gcc_assert (from == FRAME_POINTER_REGNUM); - return frame.stack_pointer_offset - frame.frame_pointer_offset; + else if (from != FRAME_POINTER_REGNUM) + abort (); + else + return frame.stack_pointer_offset - frame.frame_pointer_offset; } } @@ -5077,20 +5019,17 @@ static void ix86_compute_frame_layout (struct ix86_frame *frame) { HOST_WIDE_INT total_size; - unsigned int stack_alignment_needed; + int stack_alignment_needed = cfun->stack_alignment_needed / BITS_PER_UNIT; HOST_WIDE_INT offset; - unsigned int preferred_alignment; + int preferred_alignment = cfun->preferred_stack_boundary / BITS_PER_UNIT; HOST_WIDE_INT size = get_frame_size (); frame->nregs = ix86_nsaved_regs (); total_size = size; - stack_alignment_needed = cfun->stack_alignment_needed / BITS_PER_UNIT; - preferred_alignment = cfun->preferred_stack_boundary / BITS_PER_UNIT; - /* During reload iteration the amount of registers saved can change. Recompute the value as needed. Do not recompute when amount of registers - didn't change as reload does multiple calls to the function and does not + didn't change as reload does mutiple calls to the function and does not expect the decision to change within single iteration. */ if (!optimize_size && cfun->machine->use_fast_prologue_epilogue_nregs != frame->nregs) @@ -5134,11 +5073,14 @@ ix86_compute_frame_layout (struct ix86_frame *frame) preferred_alignment, since i386 port is the only using those features that may break easily. */ - gcc_assert (!size || stack_alignment_needed); - gcc_assert (preferred_alignment >= STACK_BOUNDARY / BITS_PER_UNIT); - gcc_assert (preferred_alignment <= PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT); - gcc_assert (stack_alignment_needed - <= PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT); + if (size && !stack_alignment_needed) + abort (); + if (preferred_alignment < STACK_BOUNDARY / BITS_PER_UNIT) + abort (); + if (preferred_alignment > PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) + abort (); + if (stack_alignment_needed > PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) + abort (); if (stack_alignment_needed < STACK_BOUNDARY / BITS_PER_UNIT) stack_alignment_needed = STACK_BOUNDARY / BITS_PER_UNIT; @@ -5172,8 +5114,7 @@ ix86_compute_frame_layout (struct ix86_frame *frame) expander assumes that last current_function_outgoing_args_size of stack frame are unused. */ if (ACCUMULATE_OUTGOING_ARGS - && (!current_function_is_leaf || current_function_calls_alloca - || ix86_current_function_calls_tls_descriptor)) + && (!current_function_is_leaf || current_function_calls_alloca)) { offset += current_function_outgoing_args_size; frame->outgoing_arguments_size = current_function_outgoing_args_size; @@ -5183,8 +5124,7 @@ ix86_compute_frame_layout (struct ix86_frame *frame) /* Align stack boundary. Only needed if we're calling another function or using alloca. */ - if (!current_function_is_leaf || current_function_calls_alloca - || ix86_current_function_calls_tls_descriptor) + if (!current_function_is_leaf || current_function_calls_alloca) frame->padding2 = ((offset + preferred_alignment - 1) & -preferred_alignment) - offset; else @@ -5205,8 +5145,7 @@ ix86_compute_frame_layout (struct ix86_frame *frame) frame->save_regs_using_mov = false; if (TARGET_RED_ZONE && current_function_sp_is_unchanging - && current_function_is_leaf - && !ix86_current_function_calls_tls_descriptor) + && current_function_is_leaf) { frame->red_zone_size = frame->to_allocate; if (frame->save_regs_using_mov) @@ -5239,10 +5178,10 @@ ix86_compute_frame_layout (struct ix86_frame *frame) static void ix86_emit_save_regs (void) { - unsigned int regno; + int regno; rtx insn; - for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; ) + for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) if (ix86_save_reg (regno, true)) { insn = emit_insn (gen_push (gen_rtx_REG (Pmode, regno))); @@ -5255,7 +5194,7 @@ ix86_emit_save_regs (void) static void ix86_emit_save_regs_using_mov (rtx pointer, HOST_WIDE_INT offset) { - unsigned int regno; + int regno; rtx insn; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) @@ -5291,7 +5230,8 @@ pro_epilogue_adjust_stack (rtx dest, rtx src, rtx offset, int style) epilogue and used after the epilogue. ATM indirect sibcall shouldn't be used together with huge frame sizes in one function because of the frame_size check in sibcall.c. */ - gcc_assert (style); + if (style == 0) + abort (); r11 = gen_rtx_REG (DImode, FIRST_REX_INT_REG + 3 /* R11 */); insn = emit_insn (gen_rtx_SET (DImode, r11, offset)); if (style < 0) @@ -5303,64 +5243,6 @@ pro_epilogue_adjust_stack (rtx dest, rtx src, rtx offset, int style) RTX_FRAME_RELATED_P (insn) = 1; } -/* Handle the TARGET_INTERNAL_ARG_POINTER hook. */ - -static rtx -ix86_internal_arg_pointer (void) -{ - bool has_force_align_arg_pointer = - (0 != lookup_attribute (ix86_force_align_arg_pointer_string, - TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))); - if ((FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN - && DECL_NAME (current_function_decl) - && MAIN_NAME_P (DECL_NAME (current_function_decl)) - && DECL_FILE_SCOPE_P (current_function_decl)) - || ix86_force_align_arg_pointer - || has_force_align_arg_pointer) - { - /* Nested functions can't realign the stack due to a register - conflict. */ - if (DECL_CONTEXT (current_function_decl) - && TREE_CODE (DECL_CONTEXT (current_function_decl)) == FUNCTION_DECL) - { - if (ix86_force_align_arg_pointer) - warning (0, "-mstackrealign ignored for nested functions"); - if (has_force_align_arg_pointer) - error ("%s not supported for nested functions", - ix86_force_align_arg_pointer_string); - return virtual_incoming_args_rtx; - } - cfun->machine->force_align_arg_pointer = gen_rtx_REG (Pmode, 2); - return copy_to_reg (cfun->machine->force_align_arg_pointer); - } - else - return virtual_incoming_args_rtx; -} - -/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook. - This is called from dwarf2out.c to emit call frame instructions - for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */ -static void -ix86_dwarf_handle_frame_unspec (const char *label, rtx pattern, int index) -{ - rtx unspec = SET_SRC (pattern); - gcc_assert (GET_CODE (unspec) == UNSPEC); - - switch (index) - { - case UNSPEC_REG_SAVE: - dwarf2out_reg_save_reg (label, XVECEXP (unspec, 0, 0), - SET_DEST (pattern)); - break; - case UNSPEC_DEF_CFA: - dwarf2out_def_cfa (label, REGNO (SET_DEST (pattern)), - INTVAL (XVECEXP (unspec, 0, 0))); - break; - default: - gcc_unreachable (); - } -} - /* Expand the prologue into a bunch of separate insns. */ void @@ -5373,52 +5255,6 @@ ix86_expand_prologue (void) ix86_compute_frame_layout (&frame); - if (cfun->machine->force_align_arg_pointer) - { - rtx x, y; - - /* Grab the argument pointer. */ - x = plus_constant (stack_pointer_rtx, 4); - y = cfun->machine->force_align_arg_pointer; - insn = emit_insn (gen_rtx_SET (VOIDmode, y, x)); - RTX_FRAME_RELATED_P (insn) = 1; - - /* The unwind info consists of two parts: install the fafp as the cfa, - and record the fafp as the "save register" of the stack pointer. - The later is there in order that the unwinder can see where it - should restore the stack pointer across the and insn. */ - x = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, const0_rtx), UNSPEC_DEF_CFA); - x = gen_rtx_SET (VOIDmode, y, x); - RTX_FRAME_RELATED_P (x) = 1; - y = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, stack_pointer_rtx), - UNSPEC_REG_SAVE); - y = gen_rtx_SET (VOIDmode, cfun->machine->force_align_arg_pointer, y); - RTX_FRAME_RELATED_P (y) = 1; - x = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x, y)); - x = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, x, NULL); - REG_NOTES (insn) = x; - - /* Align the stack. */ - emit_insn (gen_andsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (-16))); - - /* And here we cheat like madmen with the unwind info. We force the - cfa register back to sp+4, which is exactly what it was at the - start of the function. Re-pushing the return address results in - the return at the same spot relative to the cfa, and thus is - correct wrt the unwind info. */ - x = cfun->machine->force_align_arg_pointer; - x = gen_frame_mem (Pmode, plus_constant (x, -4)); - insn = emit_insn (gen_push (x)); - RTX_FRAME_RELATED_P (insn) = 1; - - x = GEN_INT (4); - x = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, x), UNSPEC_DEF_CFA); - x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x); - x = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, x, NULL); - REG_NOTES (insn) = x; - } - /* Note: AT&T enter does NOT have reversed args. Enter is probably slower on all targets. Also sdb doesn't like it. */ @@ -5455,9 +5291,9 @@ ix86_expand_prologue (void) /* Only valid for Win32. */ rtx eax = gen_rtx_REG (SImode, 0); bool eax_live = ix86_eax_live_at_start_p (); - rtx t; - gcc_assert (!TARGET_64BIT); + if (TARGET_64BIT) + abort (); if (eax_live) { @@ -5465,24 +5301,15 @@ ix86_expand_prologue (void) allocate -= 4; } - emit_move_insn (eax, GEN_INT (allocate)); + insn = emit_move_insn (eax, GEN_INT (allocate)); + RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_allocate_stack_worker (eax)); RTX_FRAME_RELATED_P (insn) = 1; - t = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (-allocate)); - t = gen_rtx_SET (VOIDmode, stack_pointer_rtx, t); - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, - t, REG_NOTES (insn)); if (eax_live) { - if (frame_pointer_needed) - t = plus_constant (hard_frame_pointer_rtx, - allocate - - frame.to_allocate - - frame.nregs * UNITS_PER_WORD); - else - t = plus_constant (stack_pointer_rtx, allocate); + rtx t = plus_constant (stack_pointer_rtx, allocate); emit_move_insn (eax, gen_rtx_MEM (SImode, t)); } } @@ -5511,10 +5338,7 @@ ix86_expand_prologue (void) if (pic_reg_used) { - if (TARGET_64BIT) - insn = emit_insn (gen_set_got_rex64 (pic_offset_table_rtx)); - else - insn = emit_insn (gen_set_got (pic_offset_table_rtx)); + insn = emit_insn (gen_set_got (pic_offset_table_rtx)); /* Even with accurate pre-reload life analysis, we can wind up deleting all references to the pic register after reload. @@ -5666,7 +5490,8 @@ ix86_expand_epilogue (int style) pop the registers. */ if (!sp_valid) { - gcc_assert (frame_pointer_needed); + if (!frame_pointer_needed) + abort (); pro_epilogue_adjust_stack (stack_pointer_rtx, hard_frame_pointer_rtx, GEN_INT (offset), style); @@ -5696,13 +5521,6 @@ ix86_expand_epilogue (int style) } } - if (cfun->machine->force_align_arg_pointer) - { - emit_insn (gen_addsi3 (stack_pointer_rtx, - cfun->machine->force_align_arg_pointer, - GEN_INT (-4))); - } - /* Sibcall epilogues don't want a return instruction. */ if (style == 0) return; @@ -5720,7 +5538,8 @@ ix86_expand_epilogue (int style) rtx ecx = gen_rtx_REG (SImode, 2); /* There is no "pascal" calling convention in 64bit ABI. */ - gcc_assert (!TARGET_64BIT); + if (TARGET_64BIT) + abort (); emit_insn (gen_popsi1 (ecx)); emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, popc)); @@ -5741,23 +5560,6 @@ ix86_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, { if (pic_offset_table_rtx) REGNO (pic_offset_table_rtx) = REAL_PIC_OFFSET_TABLE_REGNUM; -#if TARGET_MACHO - /* Mach-O doesn't support labels at the end of objects, so if - it looks like we might want one, insert a NOP. */ - { - rtx insn = get_last_insn (); - while (insn - && NOTE_P (insn) - && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL) - insn = PREV_INSN (insn); - if (insn - && (LABEL_P (insn) - || (NOTE_P (insn) - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL))) - fputs ("\tnop\n", file); - } -#endif - } /* Extract the parts of an RTL expression that is a valid memory address @@ -5765,11 +5567,12 @@ ix86_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, grossly off. Return -1 if the address contains ASHIFT, so it is not strictly valid, but still used for computing length of lea instruction. */ -int +static int ix86_decompose_address (rtx addr, struct ix86_address *out) { - rtx base = NULL_RTX, index = NULL_RTX, disp = NULL_RTX; - rtx base_reg, index_reg; + rtx base = NULL_RTX; + rtx index = NULL_RTX; + rtx disp = NULL_RTX; HOST_WIDE_INT scale = 1; rtx scale_rtx = NULL_RTX; int retval = 1; @@ -5871,37 +5674,34 @@ ix86_decompose_address (rtx addr, struct ix86_address *out) scale = INTVAL (scale_rtx); } - base_reg = base && GET_CODE (base) == SUBREG ? SUBREG_REG (base) : base; - index_reg = index && GET_CODE (index) == SUBREG ? SUBREG_REG (index) : index; - /* Allow arg pointer and stack pointer as index if there is not scaling. */ - if (base_reg && index_reg && scale == 1 - && (index_reg == arg_pointer_rtx - || index_reg == frame_pointer_rtx - || (REG_P (index_reg) && REGNO (index_reg) == STACK_POINTER_REGNUM))) + if (base && index && scale == 1 + && (index == arg_pointer_rtx + || index == frame_pointer_rtx + || (REG_P (index) && REGNO (index) == STACK_POINTER_REGNUM))) { - rtx tmp; - tmp = base, base = index, index = tmp; - tmp = base_reg, base_reg = index_reg, index_reg = tmp; + rtx tmp = base; + base = index; + index = tmp; } /* Special case: %ebp cannot be encoded as a base without a displacement. */ - if ((base_reg == hard_frame_pointer_rtx - || base_reg == frame_pointer_rtx - || base_reg == arg_pointer_rtx) && !disp) + if ((base == hard_frame_pointer_rtx + || base == frame_pointer_rtx + || base == arg_pointer_rtx) && !disp) disp = const0_rtx; /* Special case: on K6, [%esi] makes the instruction vector decoded. Avoid this by transforming to [%esi+0]. */ if (ix86_tune == PROCESSOR_K6 && !optimize_size - && base_reg && !index_reg && !disp - && REG_P (base_reg) - && REGNO_REG_CLASS (REGNO (base_reg)) == SIREG) + && base && !index && !disp + && REG_P (base) + && REGNO_REG_CLASS (REGNO (base)) == SIREG) disp = const0_rtx; /* Special case: encode reg+reg instead of reg*2. */ if (!base && index && scale && scale == 2) - base = index, base_reg = index_reg, scale = 1; + base = index, scale = 1; /* Special case: scaling cannot be encoded without base or displacement. */ if (!base && !disp && index && scale != 1) @@ -5926,14 +5726,9 @@ ix86_address_cost (rtx x) { struct ix86_address parts; int cost = 1; - int ok = ix86_decompose_address (x, &parts); - - gcc_assert (ok); - if (parts.base && GET_CODE (parts.base) == SUBREG) - parts.base = SUBREG_REG (parts.base); - if (parts.index && GET_CODE (parts.index) == SUBREG) - parts.index = SUBREG_REG (parts.index); + if (!ix86_decompose_address (x, &parts)) + abort (); /* More complex memory references are better. */ if (parts.disp && parts.disp != const0_rtx) @@ -6019,28 +5814,6 @@ ix86_find_base_term (rtx x) return term; } - -/* Allow {LABEL | SYMBOL}_REF - SYMBOL_REF-FOR-PICBASE for Mach-O as - this is used for to form addresses to local data when -fPIC is in - use. */ - -static bool -darwin_local_data_pic (rtx disp) -{ - if (GET_CODE (disp) == MINUS) - { - if (GET_CODE (XEXP (disp, 0)) == LABEL_REF - || GET_CODE (XEXP (disp, 0)) == SYMBOL_REF) - if (GET_CODE (XEXP (disp, 1)) == SYMBOL_REF) - { - const char *sym_name = XSTR (XEXP (disp, 1), 0); - if (! strcmp (sym_name, "<pic base>")) - return true; - } - } - - return false; -} /* Determine if a given RTX is a valid constant. We already know this satisfies CONSTANT_P. */ @@ -6060,53 +5833,30 @@ legitimate_constant_p (rtx x) x = XEXP (x, 0); } - if (TARGET_MACHO && darwin_local_data_pic (x)) - return true; - /* Only some unspecs are valid as "constants". */ if (GET_CODE (x) == UNSPEC) switch (XINT (x, 1)) { - case UNSPEC_GOTOFF: - return TARGET_64BIT; case UNSPEC_TPOFF: case UNSPEC_NTPOFF: - x = XVECEXP (x, 0, 0); - return (GET_CODE (x) == SYMBOL_REF - && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_EXEC); + return local_exec_symbolic_operand (XVECEXP (x, 0, 0), Pmode); case UNSPEC_DTPOFF: - x = XVECEXP (x, 0, 0); - return (GET_CODE (x) == SYMBOL_REF - && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC); + return local_dynamic_symbolic_operand (XVECEXP (x, 0, 0), Pmode); default: return false; } /* We must have drilled down to a symbol. */ - if (GET_CODE (x) == LABEL_REF) - return true; - if (GET_CODE (x) != SYMBOL_REF) + if (!symbolic_operand (x, Pmode)) return false; /* FALLTHRU */ case SYMBOL_REF: /* TLS symbols are never valid. */ - if (SYMBOL_REF_TLS_MODEL (x)) + if (tls_symbolic_operand (x, Pmode)) return false; break; - case CONST_DOUBLE: - if (GET_MODE (x) == TImode - && x != CONST0_RTX (TImode) - && !TARGET_64BIT) - return false; - break; - - case CONST_VECTOR: - if (x == CONST0_RTX (GET_MODE (x))) - return true; - return false; - default: break; } @@ -6122,17 +5872,6 @@ legitimate_constant_p (rtx x) static bool ix86_cannot_force_const_mem (rtx x) { - /* We can always put integral constants and vectors in memory. */ - switch (GET_CODE (x)) - { - case CONST_INT: - case CONST_DOUBLE: - case CONST_VECTOR: - return false; - - default: - break; - } return !legitimate_constant_p (x); } @@ -6157,20 +5896,13 @@ legitimate_pic_operand_p (rtx x) { case CONST: inner = XEXP (x, 0); - if (GET_CODE (inner) == PLUS - && GET_CODE (XEXP (inner, 1)) == CONST_INT) - inner = XEXP (inner, 0); /* Only some unspecs are valid as "constants". */ if (GET_CODE (inner) == UNSPEC) switch (XINT (inner, 1)) { - case UNSPEC_GOTOFF: - return TARGET_64BIT; case UNSPEC_TPOFF: - x = XVECEXP (inner, 0, 0); - return (GET_CODE (x) == SYMBOL_REF - && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_EXEC); + return local_exec_symbolic_operand (XVECEXP (inner, 0, 0), Pmode); default: return false; } @@ -6197,38 +5929,32 @@ legitimate_pic_address_disp_p (rtx disp) when they are not dynamic symbols. */ if (TARGET_64BIT) { - rtx op0 = disp, op1; - - switch (GET_CODE (disp)) + /* TLS references should always be enclosed in UNSPEC. */ + if (tls_symbolic_operand (disp, GET_MODE (disp))) + return 0; + if (GET_CODE (disp) == SYMBOL_REF + && ix86_cmodel == CM_SMALL_PIC + && SYMBOL_REF_LOCAL_P (disp)) + return 1; + if (GET_CODE (disp) == LABEL_REF) + return 1; + if (GET_CODE (disp) == CONST + && GET_CODE (XEXP (disp, 0)) == PLUS) { - case LABEL_REF: - return true; + rtx op0 = XEXP (XEXP (disp, 0), 0); + rtx op1 = XEXP (XEXP (disp, 0), 1); - case CONST: - if (GET_CODE (XEXP (disp, 0)) != PLUS) - break; - op0 = XEXP (XEXP (disp, 0), 0); - op1 = XEXP (XEXP (disp, 0), 1); - if (GET_CODE (op1) != CONST_INT - || INTVAL (op1) >= 16*1024*1024 - || INTVAL (op1) < -16*1024*1024) - break; - if (GET_CODE (op0) == LABEL_REF) - return true; - if (GET_CODE (op0) != SYMBOL_REF) - break; - /* FALLTHRU */ - - case SYMBOL_REF: /* TLS references should always be enclosed in UNSPEC. */ - if (SYMBOL_REF_TLS_MODEL (op0)) - return false; - if (!SYMBOL_REF_FAR_ADDR_P (op0) && SYMBOL_REF_LOCAL_P (op0)) - return true; - break; - - default: - break; + if (tls_symbolic_operand (op0, GET_MODE (op0))) + return 0; + if (((GET_CODE (op0) == SYMBOL_REF + && ix86_cmodel == CM_SMALL_PIC + && SYMBOL_REF_LOCAL_P (op0)) + || GET_CODE (op0) == LABEL_REF) + && GET_CODE (op1) == CONST_INT + && INTVAL (op1) < 16*1024*1024 + && INTVAL (op1) >= -16*1024*1024) + return 1; } } if (GET_CODE (disp) != CONST) @@ -6240,8 +5966,7 @@ legitimate_pic_address_disp_p (rtx disp) /* We are unsafe to allow PLUS expressions. This limit allowed distance of GOT tables. We should not need these anyway. */ if (GET_CODE (disp) != UNSPEC - || (XINT (disp, 1) != UNSPEC_GOTPCREL - && XINT (disp, 1) != UNSPEC_GOTOFF)) + || XINT (disp, 1) != UNSPEC_GOTPCREL) return 0; if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF @@ -6259,8 +5984,18 @@ legitimate_pic_address_disp_p (rtx disp) saw_plus = true; } - if (TARGET_MACHO && darwin_local_data_pic (disp)) - return 1; + /* Allow {LABEL | SYMBOL}_REF - SYMBOL_REF-FOR-PICBASE for Mach-O. */ + if (TARGET_MACHO && GET_CODE (disp) == MINUS) + { + if (GET_CODE (XEXP (disp, 0)) == LABEL_REF + || GET_CODE (XEXP (disp, 0)) == SYMBOL_REF) + if (GET_CODE (XEXP (disp, 1)) == SYMBOL_REF) + { + const char *sym_name = XSTR (XEXP (disp, 1), 0); + if (! strcmp (sym_name, "<pic base>")) + return 1; + } + } if (GET_CODE (disp) != UNSPEC) return 0; @@ -6272,12 +6007,8 @@ legitimate_pic_address_disp_p (rtx disp) return false; return GET_CODE (XVECEXP (disp, 0, 0)) == SYMBOL_REF; case UNSPEC_GOTOFF: - /* Refuse GOTOFF in 64bit mode since it is always 64bit when used. - While ABI specify also 32bit relocation but we don't produce it in - small PIC model at all. */ - if ((GET_CODE (XVECEXP (disp, 0, 0)) == SYMBOL_REF - || GET_CODE (XVECEXP (disp, 0, 0)) == LABEL_REF) - && !TARGET_64BIT) + if (GET_CODE (XVECEXP (disp, 0, 0)) == SYMBOL_REF + || GET_CODE (XVECEXP (disp, 0, 0)) == LABEL_REF) return local_symbolic_operand (XVECEXP (disp, 0, 0), Pmode); return false; case UNSPEC_GOTTPOFF: @@ -6285,17 +6016,11 @@ legitimate_pic_address_disp_p (rtx disp) case UNSPEC_INDNTPOFF: if (saw_plus) return false; - disp = XVECEXP (disp, 0, 0); - return (GET_CODE (disp) == SYMBOL_REF - && SYMBOL_REF_TLS_MODEL (disp) == TLS_MODEL_INITIAL_EXEC); + return initial_exec_symbolic_operand (XVECEXP (disp, 0, 0), Pmode); case UNSPEC_NTPOFF: - disp = XVECEXP (disp, 0, 0); - return (GET_CODE (disp) == SYMBOL_REF - && SYMBOL_REF_TLS_MODEL (disp) == TLS_MODEL_LOCAL_EXEC); + return local_exec_symbolic_operand (XVECEXP (disp, 0, 0), Pmode); case UNSPEC_DTPOFF: - disp = XVECEXP (disp, 0, 0); - return (GET_CODE (disp) == SYMBOL_REF - && SYMBOL_REF_TLS_MODEL (disp) == TLS_MODEL_LOCAL_DYNAMIC); + return local_dynamic_symbolic_operand (XVECEXP (disp, 0, 0), Pmode); } return 0; @@ -6339,23 +6064,15 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict) /* Validate base register. - Don't allow SUBREG's that span more than a word here. It can lead to spill - failures when the base is one word out of a two word structure, which is - represented internally as a DImode int. */ + Don't allow SUBREG's here, it can lead to spill failures when the base + is one word out of a two word structure, which is represented internally + as a DImode int. */ if (base) { - rtx reg; reason_rtx = base; - if (REG_P (base)) - reg = base; - else if (GET_CODE (base) == SUBREG - && REG_P (SUBREG_REG (base)) - && GET_MODE_SIZE (GET_MODE (SUBREG_REG (base))) - <= UNITS_PER_WORD) - reg = SUBREG_REG (base); - else + if (GET_CODE (base) != REG) { reason = "base is not a register"; goto report_error; @@ -6367,8 +6084,8 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict) goto report_error; } - if ((strict && ! REG_OK_FOR_BASE_STRICT_P (reg)) - || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (reg))) + if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base)) + || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base))) { reason = "base is not valid"; goto report_error; @@ -6377,21 +6094,15 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict) /* Validate index register. - Don't allow SUBREG's that span more than a word here -- same as above. */ + Don't allow SUBREG's here, it can lead to spill failures when the index + is one word out of a two word structure, which is represented internally + as a DImode int. */ if (index) { - rtx reg; reason_rtx = index; - if (REG_P (index)) - reg = index; - else if (GET_CODE (index) == SUBREG - && REG_P (SUBREG_REG (index)) - && GET_MODE_SIZE (GET_MODE (SUBREG_REG (index))) - <= UNITS_PER_WORD) - reg = SUBREG_REG (index); - else + if (GET_CODE (index) != REG) { reason = "index is not a register"; goto report_error; @@ -6403,8 +6114,8 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict) goto report_error; } - if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (reg)) - || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (reg))) + if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (index)) + || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (index))) { reason = "index is not valid"; goto report_error; @@ -6437,19 +6148,11 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict) && GET_CODE (XEXP (disp, 0)) == UNSPEC) switch (XINT (XEXP (disp, 0), 1)) { - /* Refuse GOTOFF and GOT in 64bit mode since it is always 64bit when - used. While ABI specify also 32bit relocations, we don't produce - them at all and use IP relative instead. */ case UNSPEC_GOT: case UNSPEC_GOTOFF: - gcc_assert (flag_pic); - if (!TARGET_64BIT) - goto is_legitimate_pic; - reason = "64bit address unspec"; - goto report_error; - case UNSPEC_GOTPCREL: - gcc_assert (flag_pic); + if (!flag_pic) + abort (); goto is_legitimate_pic; case UNSPEC_GOTTPOFF: @@ -6464,16 +6167,12 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict) goto report_error; } - else if (SYMBOLIC_CONST (disp) - && (flag_pic - || (TARGET_MACHO + else if (flag_pic && (SYMBOLIC_CONST (disp) #if TARGET_MACHO - && MACHOPIC_INDIRECT - && !machopic_operand_p (disp) + && !machopic_operand_p (disp) #endif - ))) + )) { - is_legitimate_pic: if (TARGET_64BIT && (index || base)) { @@ -6527,8 +6226,7 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict) reason = "displacement is not constant"; goto report_error; } - else if (TARGET_64BIT - && !x86_64_immediate_operand (disp, VOIDmode)) + else if (TARGET_64BIT && !x86_64_sign_extended_value (disp)) { reason = "displacement is out of range"; goto report_error; @@ -6549,7 +6247,7 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict) return FALSE; } -/* Return a unique alias set for the GOT. */ +/* Return an unique alias set for the GOT. */ static HOST_WIDE_INT ix86_GOT_alias_set (void) @@ -6578,7 +6276,7 @@ ix86_GOT_alias_set (void) GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC reg also appears in the address. */ -static rtx +rtx legitimize_pic_address (rtx orig, rtx reg) { rtx addr = orig; @@ -6586,51 +6284,14 @@ legitimize_pic_address (rtx orig, rtx reg) rtx base; #if TARGET_MACHO - if (TARGET_MACHO && !TARGET_64BIT) - { - if (reg == 0) - reg = gen_reg_rtx (Pmode); - /* Use the generic Mach-O PIC machinery. */ - return machopic_legitimize_pic_address (orig, GET_MODE (orig), reg); - } + if (reg == 0) + reg = gen_reg_rtx (Pmode); + /* Use the generic Mach-O PIC machinery. */ + return machopic_legitimize_pic_address (orig, GET_MODE (orig), reg); #endif if (TARGET_64BIT && legitimate_pic_address_disp_p (addr)) new = addr; - else if (TARGET_64BIT - && ix86_cmodel != CM_SMALL_PIC - && local_symbolic_operand (addr, Pmode)) - { - rtx tmpreg; - /* This symbol may be referenced via a displacement from the PIC - base address (@GOTOFF). */ - - if (reload_in_progress) - regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; - if (GET_CODE (addr) == CONST) - addr = XEXP (addr, 0); - if (GET_CODE (addr) == PLUS) - { - new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (addr, 0)), UNSPEC_GOTOFF); - new = gen_rtx_PLUS (Pmode, new, XEXP (addr, 1)); - } - else - new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF); - new = gen_rtx_CONST (Pmode, new); - if (!reg) - tmpreg = gen_reg_rtx (Pmode); - else - tmpreg = reg; - emit_move_insn (tmpreg, new); - - if (reg != 0) - { - new = expand_simple_binop (Pmode, PLUS, reg, pic_offset_table_rtx, - tmpreg, 1, OPTAB_DIRECT); - new = reg; - } - else new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmpreg); - } else if (!TARGET_64BIT && local_symbolic_operand (addr, Pmode)) { /* This symbol may be referenced via a displacement from the PIC @@ -6656,13 +6317,14 @@ legitimize_pic_address (rtx orig, rtx reg) new = reg; } } - else if (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (addr) == 0) + else if (GET_CODE (addr) == SYMBOL_REF) { if (TARGET_64BIT) { new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTPCREL); new = gen_rtx_CONST (Pmode, new); - new = gen_const_mem (Pmode, new); + new = gen_rtx_MEM (Pmode, new); + RTX_UNCHANGING_P (new) = 1; set_mem_alias_set (new, ix86_GOT_alias_set ()); if (reg == 0) @@ -6683,7 +6345,8 @@ legitimize_pic_address (rtx orig, rtx reg) new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT); new = gen_rtx_CONST (Pmode, new); new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); - new = gen_const_mem (Pmode, new); + new = gen_rtx_MEM (Pmode, new); + RTX_UNCHANGING_P (new) = 1; set_mem_alias_set (new, ix86_GOT_alias_set ()); if (reg == 0) @@ -6694,18 +6357,7 @@ legitimize_pic_address (rtx orig, rtx reg) } else { - if (GET_CODE (addr) == CONST_INT - && !x86_64_immediate_operand (addr, VOIDmode)) - { - if (reg) - { - emit_move_insn (reg, addr); - new = reg; - } - else - new = force_reg (Pmode, addr); - } - else if (GET_CODE (addr) == CONST) + if (GET_CODE (addr) == CONST) { addr = XEXP (addr, 0); @@ -6716,7 +6368,8 @@ legitimize_pic_address (rtx orig, rtx reg) || (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 0)) == UNSPEC)) return orig; - gcc_assert (GET_CODE (addr) == PLUS); + if (GET_CODE (addr) != PLUS) + abort (); } if (GET_CODE (addr) == PLUS) { @@ -6747,11 +6400,7 @@ legitimize_pic_address (rtx orig, rtx reg) { if (INTVAL (op1) < -16*1024*1024 || INTVAL (op1) >= 16*1024*1024) - { - if (!x86_64_immediate_operand (op1, Pmode)) - op1 = force_reg (Pmode, op1); - new = gen_rtx_PLUS (Pmode, force_reg (Pmode, op0), op1); - } + new = gen_rtx_PLUS (Pmode, op0, force_reg (Pmode, op1)); } } else @@ -6802,16 +6451,14 @@ get_thread_pointer (int to_reg) static rtx legitimize_tls_address (rtx x, enum tls_model model, int for_mov) { - rtx dest, base, off, pic, tp; + rtx dest, base, off, pic; int type; switch (model) { case TLS_MODEL_GLOBAL_DYNAMIC: dest = gen_reg_rtx (Pmode); - tp = TARGET_GNU2_TLS ? get_thread_pointer (1) : 0; - - if (TARGET_64BIT && ! TARGET_GNU2_TLS) + if (TARGET_64BIT) { rtx rax = gen_rtx_REG (Pmode, 0), insns; @@ -6822,24 +6469,13 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) emit_libcall_block (insns, dest, rax, x); } - else if (TARGET_64BIT && TARGET_GNU2_TLS) - emit_insn (gen_tls_global_dynamic_64 (dest, x)); else emit_insn (gen_tls_global_dynamic_32 (dest, x)); - - if (TARGET_GNU2_TLS) - { - dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, tp, dest)); - - set_unique_reg_note (get_last_insn (), REG_EQUIV, x); - } break; case TLS_MODEL_LOCAL_DYNAMIC: base = gen_reg_rtx (Pmode); - tp = TARGET_GNU2_TLS ? get_thread_pointer (1) : 0; - - if (TARGET_64BIT && ! TARGET_GNU2_TLS) + if (TARGET_64BIT) { rtx rax = gen_rtx_REG (Pmode, 0), insns, note; @@ -6852,32 +6488,13 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) note = gen_rtx_EXPR_LIST (VOIDmode, ix86_tls_get_addr (), note); emit_libcall_block (insns, base, rax, note); } - else if (TARGET_64BIT && TARGET_GNU2_TLS) - emit_insn (gen_tls_local_dynamic_base_64 (base)); else emit_insn (gen_tls_local_dynamic_base_32 (base)); - if (TARGET_GNU2_TLS) - { - rtx x = ix86_tls_module_base (); - - set_unique_reg_note (get_last_insn (), REG_EQUIV, - gen_rtx_MINUS (Pmode, x, tp)); - } - off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPOFF); off = gen_rtx_CONST (Pmode, off); - dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, off)); - - if (TARGET_GNU2_TLS) - { - dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, dest, tp)); - - set_unique_reg_note (get_last_insn (), REG_EQUIV, x); - } - - break; + return gen_rtx_PLUS (Pmode, base, off); case TLS_MODEL_INITIAL_EXEC: if (TARGET_64BIT) @@ -6890,9 +6507,9 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) if (reload_in_progress) regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; pic = pic_offset_table_rtx; - type = TARGET_ANY_GNU_TLS ? UNSPEC_GOTNTPOFF : UNSPEC_GOTTPOFF; + type = TARGET_GNU_TLS ? UNSPEC_GOTNTPOFF : UNSPEC_GOTTPOFF; } - else if (!TARGET_ANY_GNU_TLS) + else if (!TARGET_GNU_TLS) { pic = gen_reg_rtx (Pmode); emit_insn (gen_set_got (pic)); @@ -6908,10 +6525,11 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) off = gen_rtx_CONST (Pmode, off); if (pic) off = gen_rtx_PLUS (Pmode, pic, off); - off = gen_const_mem (Pmode, off); + off = gen_rtx_MEM (Pmode, off); + RTX_UNCHANGING_P (off) = 1; set_mem_alias_set (off, ix86_GOT_alias_set ()); - if (TARGET_64BIT || TARGET_ANY_GNU_TLS) + if (TARGET_64BIT || TARGET_GNU_TLS) { base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS); off = force_reg (Pmode, off); @@ -6927,11 +6545,11 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) case TLS_MODEL_LOCAL_EXEC: off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), - (TARGET_64BIT || TARGET_ANY_GNU_TLS) + (TARGET_64BIT || TARGET_GNU_TLS) ? UNSPEC_NTPOFF : UNSPEC_TPOFF); off = gen_rtx_CONST (Pmode, off); - if (TARGET_64BIT || TARGET_ANY_GNU_TLS) + if (TARGET_64BIT || TARGET_GNU_TLS) { base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS); return gen_rtx_PLUS (Pmode, base, off); @@ -6945,7 +6563,7 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) break; default: - gcc_unreachable (); + abort (); } return dest; @@ -6985,17 +6603,9 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode) debug_rtx (x); } - log = GET_CODE (x) == SYMBOL_REF ? SYMBOL_REF_TLS_MODEL (x) : 0; + log = tls_symbolic_operand (x, mode); if (log) return legitimize_tls_address (x, log, false); - if (GET_CODE (x) == CONST - && GET_CODE (XEXP (x, 0)) == PLUS - && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF - && (log = SYMBOL_REF_TLS_MODEL (XEXP (XEXP (x, 0), 0)))) - { - rtx t = legitimize_tls_address (XEXP (XEXP (x, 0), 0), log, false); - return gen_rtx_PLUS (Pmode, t, XEXP (XEXP (x, 0), 1)); - } if (flag_pic && SYMBOLIC_CONST (x)) return legitimize_pic_address (x, 0); @@ -7003,10 +6613,9 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode) /* Canonicalize shifts by 0, 1, 2, 3 into multiply */ if (GET_CODE (x) == ASHIFT && GET_CODE (XEXP (x, 1)) == CONST_INT - && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) < 4) + && (log = (unsigned) exact_log2 (INTVAL (XEXP (x, 1)))) < 4) { changed = 1; - log = INTVAL (XEXP (x, 1)); x = gen_rtx_MULT (Pmode, force_reg (Pmode, XEXP (x, 0)), GEN_INT (1 << log)); } @@ -7017,10 +6626,9 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode) if (GET_CODE (XEXP (x, 0)) == ASHIFT && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT - && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (x, 0), 1)) < 4) + && (log = (unsigned) exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) < 4) { changed = 1; - log = INTVAL (XEXP (XEXP (x, 0), 1)); XEXP (x, 0) = gen_rtx_MULT (Pmode, force_reg (Pmode, XEXP (XEXP (x, 0), 0)), GEN_INT (1 << log)); @@ -7028,10 +6636,9 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode) if (GET_CODE (XEXP (x, 1)) == ASHIFT && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT - && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (x, 1), 1)) < 4) + && (log = (unsigned) exact_log2 (INTVAL (XEXP (XEXP (x, 1), 1)))) < 4) { changed = 1; - log = INTVAL (XEXP (XEXP (x, 1), 1)); XEXP (x, 1) = gen_rtx_MULT (Pmode, force_reg (Pmode, XEXP (XEXP (x, 1), 0)), GEN_INT (1 << log)); @@ -7161,28 +6768,14 @@ output_pic_addr_const (FILE *file, rtx x, int code) switch (GET_CODE (x)) { case PC: - gcc_assert (flag_pic); - putc ('.', file); + if (flag_pic) + putc ('.', file); + else + abort (); break; case SYMBOL_REF: - if (! TARGET_MACHO || TARGET_64BIT) - output_addr_const (file, x); - else - { - const char *name = XSTR (x, 0); - - /* Mark the decl as referenced so that cgraph will output the function. */ - if (SYMBOL_REF_DECL (x)) - mark_decl_referenced (SYMBOL_REF_DECL (x)); - -#if TARGET_MACHO - if (MACHOPIC_INDIRECT - && machopic_classify_symbol (x) == MACHOPIC_UNDEFINED_FUNCTION) - name = machopic_indirection_name (x, /*stub_p=*/true); -#endif - assemble_name (file, name); - } + assemble_name (file, XSTR (x, 0)); if (!TARGET_MACHO && code == 'P' && ! SYMBOL_REF_LOCAL_P (x)) fputs ("@PLT", file); break; @@ -7230,13 +6823,14 @@ output_pic_addr_const (FILE *file, rtx x, int code) putc ('+', file); output_pic_addr_const (file, XEXP (x, 1), code); } - else + else if (GET_CODE (XEXP (x, 1)) == CONST_INT) { - gcc_assert (GET_CODE (XEXP (x, 1)) == CONST_INT); output_pic_addr_const (file, XEXP (x, 1), code); putc ('+', file); output_pic_addr_const (file, XEXP (x, 0), code); } + else + abort (); break; case MINUS: @@ -7250,7 +6844,8 @@ output_pic_addr_const (FILE *file, rtx x, int code) break; case UNSPEC: - gcc_assert (XVECLEN (x, 0) == 1); + if (XVECLEN (x, 0) != 1) + abort (); output_pic_addr_const (file, XVECEXP (x, 0, 0), code); switch (XINT (x, 1)) { @@ -7299,10 +6894,30 @@ output_pic_addr_const (FILE *file, rtx x, int code) } } -/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL. +/* This is called from dwarfout.c via ASM_OUTPUT_DWARF_ADDR_CONST. + We need to handle our special PIC relocations. */ + +void +i386_dwarf_output_addr_const (FILE *file, rtx x) +{ +#ifdef ASM_QUAD + fprintf (file, "%s", TARGET_64BIT ? ASM_QUAD : ASM_LONG); +#else + if (TARGET_64BIT) + abort (); + fprintf (file, "%s", ASM_LONG); +#endif + if (flag_pic) + output_pic_addr_const (file, x, '\0'); + else + output_addr_const (file, x); + fputc ('\n', file); +} + +/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL. We need to emit DTP-relative relocations. */ -static void +void i386_output_dwarf_dtprel (FILE *file, int size, rtx x) { fputs (ASM_LONG, file); @@ -7316,30 +6931,18 @@ i386_output_dwarf_dtprel (FILE *file, int size, rtx x) fputs (", 0", file); break; default: - gcc_unreachable (); + abort (); } } /* In the name of slightly smaller debug output, and to cater to - general assembler lossage, recognize PIC+GOTOFF and turn it back - into a direct symbol reference. - - On Darwin, this is necessary to avoid a crash, because Darwin - has a different PIC label for each routine but the DWARF debugging - information is not associated with any particular routine, so it's - necessary to remove references to the PIC label from RTL stored by - the DWARF output code. */ + general assembler losage, recognize PIC+GOTOFF and turn it back + into a direct symbol reference. */ static rtx ix86_delegitimize_address (rtx orig_x) { - rtx x = orig_x; - /* reg_addend is NULL or a multiple of some register. */ - rtx reg_addend = NULL_RTX; - /* const_addend is NULL or a const_int. */ - rtx const_addend = NULL_RTX; - /* This is the result, or NULL. */ - rtx result = NULL_RTX; + rtx x = orig_x, y; if (GET_CODE (x) == MEM) x = XEXP (x, 0); @@ -7361,52 +6964,51 @@ ix86_delegitimize_address (rtx orig_x) if (GET_CODE (XEXP (x, 0)) == REG && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM) /* %ebx + GOT/GOTOFF */ - ; + y = NULL; else if (GET_CODE (XEXP (x, 0)) == PLUS) { /* %ebx + %reg * scale + GOT/GOTOFF */ - reg_addend = XEXP (x, 0); - if (GET_CODE (XEXP (reg_addend, 0)) == REG - && REGNO (XEXP (reg_addend, 0)) == PIC_OFFSET_TABLE_REGNUM) - reg_addend = XEXP (reg_addend, 1); - else if (GET_CODE (XEXP (reg_addend, 1)) == REG - && REGNO (XEXP (reg_addend, 1)) == PIC_OFFSET_TABLE_REGNUM) - reg_addend = XEXP (reg_addend, 0); + y = XEXP (x, 0); + if (GET_CODE (XEXP (y, 0)) == REG + && REGNO (XEXP (y, 0)) == PIC_OFFSET_TABLE_REGNUM) + y = XEXP (y, 1); + else if (GET_CODE (XEXP (y, 1)) == REG + && REGNO (XEXP (y, 1)) == PIC_OFFSET_TABLE_REGNUM) + y = XEXP (y, 0); else return orig_x; - if (GET_CODE (reg_addend) != REG - && GET_CODE (reg_addend) != MULT - && GET_CODE (reg_addend) != ASHIFT) + if (GET_CODE (y) != REG + && GET_CODE (y) != MULT + && GET_CODE (y) != ASHIFT) return orig_x; } else return orig_x; x = XEXP (XEXP (x, 1), 0); - if (GET_CODE (x) == PLUS - && GET_CODE (XEXP (x, 1)) == CONST_INT) - { - const_addend = XEXP (x, 1); - x = XEXP (x, 0); - } - if (GET_CODE (x) == UNSPEC && ((XINT (x, 1) == UNSPEC_GOT && GET_CODE (orig_x) == MEM) || (XINT (x, 1) == UNSPEC_GOTOFF && GET_CODE (orig_x) != MEM))) - result = XVECEXP (x, 0, 0); - - if (TARGET_MACHO && darwin_local_data_pic (x) - && GET_CODE (orig_x) != MEM) - result = XEXP (x, 0); + { + if (y) + return gen_rtx_PLUS (Pmode, y, XVECEXP (x, 0, 0)); + return XVECEXP (x, 0, 0); + } - if (! result) - return orig_x; + if (GET_CODE (x) == PLUS + && GET_CODE (XEXP (x, 0)) == UNSPEC + && GET_CODE (XEXP (x, 1)) == CONST_INT + && ((XINT (XEXP (x, 0), 1) == UNSPEC_GOT && GET_CODE (orig_x) == MEM) + || (XINT (XEXP (x, 0), 1) == UNSPEC_GOTOFF + && GET_CODE (orig_x) != MEM))) + { + x = gen_rtx_PLUS (VOIDmode, XVECEXP (XEXP (x, 0), 0, 0), XEXP (x, 1)); + if (y) + return gen_rtx_PLUS (Pmode, y, x); + return x; + } - if (const_addend) - result = gen_rtx_PLUS (Pmode, result, const_addend); - if (reg_addend) - result = gen_rtx_PLUS (Pmode, reg_addend, result); - return result; + return orig_x; } static void @@ -7419,7 +7021,8 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse, { enum rtx_code second_code, bypass_code; ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code); - gcc_assert (bypass_code == UNKNOWN && second_code == UNKNOWN); + if (bypass_code != NIL || second_code != NIL) + abort (); code = ix86_fp_compare_code_to_integer (code); mode = CCmode; } @@ -7435,64 +7038,52 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse, suffix = "ne"; break; case GT: - gcc_assert (mode == CCmode || mode == CCNOmode || mode == CCGCmode); + if (mode != CCmode && mode != CCNOmode && mode != CCGCmode) + abort (); suffix = "g"; break; case GTU: - /* ??? Use "nbe" instead of "a" for fcmov lossage on some assemblers. - Those same assemblers have the same but opposite lossage on cmov. */ - gcc_assert (mode == CCmode); + /* ??? Use "nbe" instead of "a" for fcmov losage on some assemblers. + Those same assemblers have the same but opposite losage on cmov. */ + if (mode != CCmode) + abort (); suffix = fp ? "nbe" : "a"; break; case LT: - switch (mode) - { - case CCNOmode: - case CCGOCmode: - suffix = "s"; - break; - - case CCmode: - case CCGCmode: - suffix = "l"; - break; - - default: - gcc_unreachable (); - } + if (mode == CCNOmode || mode == CCGOCmode) + suffix = "s"; + else if (mode == CCmode || mode == CCGCmode) + suffix = "l"; + else + abort (); break; case LTU: - gcc_assert (mode == CCmode); + if (mode != CCmode) + abort (); suffix = "b"; break; case GE: - switch (mode) - { - case CCNOmode: - case CCGOCmode: - suffix = "ns"; - break; - - case CCmode: - case CCGCmode: - suffix = "ge"; - break; - - default: - gcc_unreachable (); - } + if (mode == CCNOmode || mode == CCGOCmode) + suffix = "ns"; + else if (mode == CCmode || mode == CCGCmode) + suffix = "ge"; + else + abort (); break; case GEU: /* ??? As above. */ - gcc_assert (mode == CCmode); + if (mode != CCmode) + abort (); suffix = fp ? "nb" : "ae"; break; case LE: - gcc_assert (mode == CCmode || mode == CCGCmode || mode == CCNOmode); + if (mode != CCmode && mode != CCGCmode && mode != CCNOmode) + abort (); suffix = "le"; break; case LEU: - gcc_assert (mode == CCmode); + if (mode != CCmode) + abort (); suffix = "be"; break; case UNORDERED: @@ -7502,7 +7093,7 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse, suffix = fp ? "nu" : "np"; break; default: - gcc_unreachable (); + abort (); } fputs (suffix, file); } @@ -7512,16 +7103,17 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse, If CODE is 'b', pretend the mode is QImode. If CODE is 'k', pretend the mode is SImode. If CODE is 'q', pretend the mode is DImode. - If CODE is 'h', pretend the reg is the 'high' byte register. + If CODE is 'h', pretend the reg is the `high' byte register. If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op. */ void print_reg (rtx x, int code, FILE *file) { - gcc_assert (REGNO (x) != ARG_POINTER_REGNUM - && REGNO (x) != FRAME_POINTER_REGNUM - && REGNO (x) != FLAGS_REG - && REGNO (x) != FPSR_REG); + if (REGNO (x) == ARG_POINTER_REGNUM + || REGNO (x) == FRAME_POINTER_REGNUM + || REGNO (x) == FLAGS_REG + || REGNO (x) == FPSR_REG) + abort (); if (ASSEMBLER_DIALECT == ASM_ATT || USER_LABEL_PREFIX[0] == 0) putc ('%', file); @@ -7545,7 +7137,8 @@ print_reg (rtx x, int code, FILE *file) from the normal registers. */ if (REX_INT_REG_P (x)) { - gcc_assert (TARGET_64BIT); + if (!TARGET_64BIT) + abort (); switch (code) { case 0: @@ -7600,7 +7193,7 @@ print_reg (rtx x, int code, FILE *file) fputs (qi_high_reg_name[REGNO (x)], file); break; default: - gcc_unreachable (); + abort (); } } @@ -7621,7 +7214,7 @@ get_some_local_dynamic_name (void) && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0)) return cfun->machine->some_ld_name; - gcc_unreachable (); + abort (); } static int @@ -7630,7 +7223,7 @@ get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED) rtx x = *px; if (GET_CODE (x) == SYMBOL_REF - && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC) + && local_dynamic_symbolic_operand (x, Pmode)) { cfun->machine->some_ld_name = XSTR (x, 0); return 1; @@ -7664,7 +7257,6 @@ get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED) P -- if PIC, print an @PLT suffix. X -- don't print any sort of PIC '@' suffix for a symbol. & -- print some in-use local-dynamic symbol name. - H -- print a memory address offset by 8; used for sse high-parts */ void @@ -7684,13 +7276,10 @@ print_operand (FILE *file, rtx x, int code) return; case 'A': - switch (ASSEMBLER_DIALECT) + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('*', file); + else if (ASSEMBLER_DIALECT == ASM_INTEL) { - case ASM_ATT: - putc ('*', file); - break; - - case ASM_INTEL: /* Intel syntax. For absolute addresses, registers should not be surrounded by braces. */ if (GET_CODE (x) != REG) @@ -7700,11 +7289,9 @@ print_operand (FILE *file, rtx x, int code) putc (']', file); return; } - break; - - default: - gcc_unreachable (); } + else + abort (); PRINT_OPERAND (file, x, 0); return; @@ -7789,7 +7376,7 @@ print_operand (FILE *file, rtx x, int code) return; default: - gcc_unreachable (); + abort (); } case 'b': @@ -7847,7 +7434,8 @@ print_operand (FILE *file, rtx x, int code) fputs ("ord", file); break; default: - gcc_unreachable (); + abort (); + break; } return; case 'O': @@ -7861,7 +7449,7 @@ print_operand (FILE *file, rtx x, int code) case SFmode: putc ('l', file); break; case DImode: case DFmode: putc ('q', file); break; - default: gcc_unreachable (); + default: abort (); } putc ('.', file); } @@ -7882,7 +7470,7 @@ print_operand (FILE *file, rtx x, int code) case 'c': /* Check to see if argument to %c is really a constant and not a condition code which needs to be reversed. */ - if (!COMPARISON_P (x)) + if (GET_RTX_CLASS (GET_CODE (x)) != '<') { output_operand_lossage ("operand is neither a constant nor a condition code, invalid operand code 'c'"); return; @@ -7896,13 +7484,6 @@ print_operand (FILE *file, rtx x, int code) #endif put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 1, file); return; - - case 'H': - /* It doesn't actually matter what mode we use here, as we're - only going to use this for printing. */ - x = adjust_address_nv (x, DImode, 8); - break; - case '+': { rtx x; @@ -7937,7 +7518,7 @@ print_operand (FILE *file, rtx x, int code) return; } default: - output_operand_lossage ("invalid operand code '%c'", code); + output_operand_lossage ("invalid operand code `%c'", code); } } @@ -7959,7 +7540,7 @@ print_operand (FILE *file, rtx x, int code) case 12: size = "XWORD"; break; case 16: size = "XMMWORD"; break; default: - gcc_unreachable (); + abort (); } /* Check for explicit size override (codes 'b', 'w' and 'k') */ @@ -8018,15 +7599,6 @@ print_operand (FILE *file, rtx x, int code) else { - /* We have patterns that allow zero sets of memory, for instance. - In 64-bit mode, we should probably support all 8-byte vectors, - since we can in fact encode that into an immediate. */ - if (GET_CODE (x) == CONST_VECTOR) - { - gcc_assert (x == CONST0_RTX (GET_MODE (x))); - x = const0_rtx; - } - if (code != 'P') { if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) @@ -8060,9 +7632,9 @@ print_operand_address (FILE *file, rtx addr) struct ix86_address parts; rtx base, index, disp; int scale; - int ok = ix86_decompose_address (addr, &parts); - gcc_assert (ok); + if (! ix86_decompose_address (addr, &parts)) + abort (); base = parts.base; index = parts.index; @@ -8080,7 +7652,7 @@ print_operand_address (FILE *file, rtx addr) fputs ((parts.seg == SEG_FS ? "fs:" : "gs:"), file); break; default: - gcc_unreachable (); + abort (); } if (!base && !index) @@ -8103,17 +7675,16 @@ print_operand_address (FILE *file, rtx addr) output_addr_const (file, disp); /* Use one byte shorter RIP relative addressing for 64bit mode. */ - if (TARGET_64BIT) - { - if (GET_CODE (disp) == CONST - && GET_CODE (XEXP (disp, 0)) == PLUS - && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT) - disp = XEXP (XEXP (disp, 0), 0); - if (GET_CODE (disp) == LABEL_REF - || (GET_CODE (disp) == SYMBOL_REF - && SYMBOL_REF_TLS_MODEL (disp) == 0)) - fputs ("(%rip)", file); - } + if (TARGET_64BIT + && ((GET_CODE (disp) == SYMBOL_REF + && ! tls_symbolic_operand (disp, GET_MODE (disp))) + || GET_CODE (disp) == LABEL_REF + || (GET_CODE (disp) == CONST + && GET_CODE (XEXP (disp, 0)) == PLUS + && (GET_CODE (XEXP (XEXP (disp, 0), 0)) == SYMBOL_REF + || GET_CODE (XEXP (XEXP (disp, 0), 0)) == LABEL_REF) + && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT))) + fputs ("(%rip)", file); } else { @@ -8276,7 +7847,7 @@ split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[]) } } } -/* Split one or more TImode RTL references into pairs of DImode +/* Split one or more TImode RTL references into pairs of SImode references. The RTL can be REG, offsettable MEM, integer constant, or CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to split and "num" is its length. lo_half and hi_half are output arrays @@ -8327,7 +7898,7 @@ output_387_binary_op (rtx insn, rtx *operands) static char buf[30]; const char *p; const char *ssep; - int is_sse = SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]) || SSE_REG_P (operands[2]); + int is_sse = SSE_REG_P (operands[0]) | SSE_REG_P (operands[1]) | SSE_REG_P (operands[2]); #ifdef ENABLE_CHECKING /* Even if we do not want to check the inputs, this documents input @@ -8341,8 +7912,8 @@ output_387_binary_op (rtx insn, rtx *operands) && (STACK_REG_P (operands[1]) || GET_CODE (operands[1]) == MEM))) && (STACK_TOP_P (operands[1]) || STACK_TOP_P (operands[2]))) ; /* ok */ - else - gcc_assert (is_sse); + else if (!is_sse) + abort (); #endif switch (GET_CODE (operands[3])) @@ -8384,7 +7955,7 @@ output_387_binary_op (rtx insn, rtx *operands) break; default: - gcc_unreachable (); + abort (); } if (is_sse) @@ -8519,153 +8090,29 @@ output_387_binary_op (rtx insn, rtx *operands) break; default: - gcc_unreachable (); + abort (); } strcat (buf, p); return buf; } -/* Return needed mode for entity in optimize_mode_switching pass. */ - -int -ix86_mode_needed (int entity, rtx insn) -{ - enum attr_i387_cw mode; - - /* The mode UNINITIALIZED is used to store control word after a - function call or ASM pattern. The mode ANY specify that function - has no requirements on the control word and make no changes in the - bits we are interested in. */ - - if (CALL_P (insn) - || (NONJUMP_INSN_P (insn) - && (asm_noperands (PATTERN (insn)) >= 0 - || GET_CODE (PATTERN (insn)) == ASM_INPUT))) - return I387_CW_UNINITIALIZED; - - if (recog_memoized (insn) < 0) - return I387_CW_ANY; - - mode = get_attr_i387_cw (insn); - - switch (entity) - { - case I387_TRUNC: - if (mode == I387_CW_TRUNC) - return mode; - break; - - case I387_FLOOR: - if (mode == I387_CW_FLOOR) - return mode; - break; - - case I387_CEIL: - if (mode == I387_CW_CEIL) - return mode; - break; - - case I387_MASK_PM: - if (mode == I387_CW_MASK_PM) - return mode; - break; - - default: - gcc_unreachable (); - } - - return I387_CW_ANY; -} - -/* Output code to initialize control word copies used by trunc?f?i and - rounding patterns. CURRENT_MODE is set to current control word, - while NEW_MODE is set to new control word. */ - +/* Output code to initialize control word copies used by + trunc?f?i patterns. NORMAL is set to current control word, while ROUND_DOWN + is set to control word rounding downwards. */ void -emit_i387_cw_initialization (int mode) +emit_i387_cw_initialization (rtx normal, rtx round_down) { - rtx stored_mode = assign_386_stack_local (HImode, SLOT_CW_STORED); - rtx new_mode; - - int slot; - rtx reg = gen_reg_rtx (HImode); - emit_insn (gen_x86_fnstcw_1 (stored_mode)); - emit_move_insn (reg, stored_mode); - - if (TARGET_64BIT || TARGET_PARTIAL_REG_STALL || optimize_size) - { - switch (mode) - { - case I387_CW_TRUNC: - /* round toward zero (truncate) */ - emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0c00))); - slot = SLOT_CW_TRUNC; - break; - - case I387_CW_FLOOR: - /* round down toward -oo */ - emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00))); - emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0400))); - slot = SLOT_CW_FLOOR; - break; - - case I387_CW_CEIL: - /* round up toward +oo */ - emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00))); - emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0800))); - slot = SLOT_CW_CEIL; - break; - - case I387_CW_MASK_PM: - /* mask precision exception for nearbyint() */ - emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0020))); - slot = SLOT_CW_MASK_PM; - break; - - default: - gcc_unreachable (); - } - } + emit_insn (gen_x86_fnstcw_1 (normal)); + emit_move_insn (reg, normal); + if (!TARGET_PARTIAL_REG_STALL && !optimize_size + && !TARGET_64BIT) + emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0xc))); else - { - switch (mode) - { - case I387_CW_TRUNC: - /* round toward zero (truncate) */ - emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0xc))); - slot = SLOT_CW_TRUNC; - break; - - case I387_CW_FLOOR: - /* round down toward -oo */ - emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0x4))); - slot = SLOT_CW_FLOOR; - break; - - case I387_CW_CEIL: - /* round up toward +oo */ - emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0x8))); - slot = SLOT_CW_CEIL; - break; - - case I387_CW_MASK_PM: - /* mask precision exception for nearbyint() */ - emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0020))); - slot = SLOT_CW_MASK_PM; - break; - - default: - gcc_unreachable (); - } - } - - gcc_assert (slot < MAX_386_STACK_LOCALS); - - new_mode = assign_386_stack_local (HImode, slot); - emit_move_insn (new_mode, reg); + emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0xc00))); + emit_move_insn (round_down, reg); } /* Output code for INSN to convert a float to a signed int. OPERANDS @@ -8673,87 +8120,50 @@ emit_i387_cw_initialization (int mode) operand may be [SDX]Fmode. */ const char * -output_fix_trunc (rtx insn, rtx *operands, int fisttp) +output_fix_trunc (rtx insn, rtx *operands) { int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; int dimode_p = GET_MODE (operands[0]) == DImode; - int round_mode = get_attr_i387_cw (insn); /* Jump through a hoop or two for DImode, since the hardware has no non-popping instruction. We used to do this a different way, but that was somewhat fragile and broke with post-reload splitters. */ - if ((dimode_p || fisttp) && !stack_top_dies) + if (dimode_p && !stack_top_dies) output_asm_insn ("fld\t%y1", operands); - gcc_assert (STACK_TOP_P (operands[1])); - gcc_assert (GET_CODE (operands[0]) == MEM); + if (!STACK_TOP_P (operands[1])) + abort (); + + if (GET_CODE (operands[0]) != MEM) + abort (); - if (fisttp) - output_asm_insn ("fisttp%z0\t%0", operands); + output_asm_insn ("fldcw\t%3", operands); + if (stack_top_dies || dimode_p) + output_asm_insn ("fistp%z0\t%0", operands); else - { - if (round_mode != I387_CW_ANY) - output_asm_insn ("fldcw\t%3", operands); - if (stack_top_dies || dimode_p) - output_asm_insn ("fistp%z0\t%0", operands); - else - output_asm_insn ("fist%z0\t%0", operands); - if (round_mode != I387_CW_ANY) - output_asm_insn ("fldcw\t%2", operands); - } + output_asm_insn ("fist%z0\t%0", operands); + output_asm_insn ("fldcw\t%2", operands); return ""; } -/* Output code for x87 ffreep insn. The OPNO argument, which may only - have the values zero or one, indicates the ffreep insn's operand - from the OPERANDS array. */ - -static const char * -output_387_ffreep (rtx *operands ATTRIBUTE_UNUSED, int opno) -{ - if (TARGET_USE_FFREEP) -#if HAVE_AS_IX86_FFREEP - return opno ? "ffreep\t%y1" : "ffreep\t%y0"; -#else - switch (REGNO (operands[opno])) - { - case FIRST_STACK_REG + 0: return ".word\t0xc0df"; - case FIRST_STACK_REG + 1: return ".word\t0xc1df"; - case FIRST_STACK_REG + 2: return ".word\t0xc2df"; - case FIRST_STACK_REG + 3: return ".word\t0xc3df"; - case FIRST_STACK_REG + 4: return ".word\t0xc4df"; - case FIRST_STACK_REG + 5: return ".word\t0xc5df"; - case FIRST_STACK_REG + 6: return ".word\t0xc6df"; - case FIRST_STACK_REG + 7: return ".word\t0xc7df"; - } -#endif - - return opno ? "fstp\t%y1" : "fstp\t%y0"; -} - - /* Output code for INSN to compare OPERANDS. EFLAGS_P is 1 when fcomi - should be used. UNORDERED_P is true when fucom should be used. */ + should be used and 2 when fnstsw should be used. UNORDERED_P is true + when fucom should be used. */ const char * output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) { int stack_top_dies; - rtx cmp_op0, cmp_op1; - int is_sse = SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]); + rtx cmp_op0 = operands[0]; + rtx cmp_op1 = operands[1]; + int is_sse = SSE_REG_P (operands[0]) | SSE_REG_P (operands[1]); - if (eflags_p) - { - cmp_op0 = operands[0]; - cmp_op1 = operands[1]; - } - else + if (eflags_p == 2) { - cmp_op0 = operands[1]; + cmp_op0 = cmp_op1; cmp_op1 = operands[2]; } - if (is_sse) { if (GET_MODE (operands[0]) == SFmode) @@ -8768,21 +8178,11 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) return "comisd\t{%1, %0|%0, %1}"; } - gcc_assert (STACK_TOP_P (cmp_op0)); + if (! STACK_TOP_P (cmp_op0)) + abort (); stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; - if (cmp_op1 == CONST0_RTX (GET_MODE (cmp_op1))) - { - if (stack_top_dies) - { - output_asm_insn ("ftst\n\tfnstsw\t%0", operands); - return output_387_ffreep (operands, 1); - } - else - return "ftst\n\tfnstsw\t%0"; - } - if (STACK_REG_P (cmp_op1) && stack_top_dies && find_regno_note (insn, REG_DEAD, REGNO (cmp_op1)) @@ -8792,7 +8192,7 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) is also a stack register that dies, then this must be a `fcompp' float compare */ - if (eflags_p) + if (eflags_p == 1) { /* There is no double popping fcomi variant. Fortunately, eflags is immune from the fstp's cc clobbering. */ @@ -8800,29 +8200,39 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) output_asm_insn ("fucomip\t{%y1, %0|%0, %y1}", operands); else output_asm_insn ("fcomip\t{%y1, %0|%0, %y1}", operands); - return output_387_ffreep (operands, 0); + return "fstp\t%y0"; } else { - if (unordered_p) - return "fucompp\n\tfnstsw\t%0"; + if (eflags_p == 2) + { + if (unordered_p) + return "fucompp\n\tfnstsw\t%0"; + else + return "fcompp\n\tfnstsw\t%0"; + } else - return "fcompp\n\tfnstsw\t%0"; + { + if (unordered_p) + return "fucompp"; + else + return "fcompp"; + } } } else { /* Encoded here as eflags_p | intmode | unordered_p | stack_top_dies. */ - static const char * const alt[16] = + static const char * const alt[24] = { - "fcom%z2\t%y2\n\tfnstsw\t%0", - "fcomp%z2\t%y2\n\tfnstsw\t%0", - "fucom%z2\t%y2\n\tfnstsw\t%0", - "fucomp%z2\t%y2\n\tfnstsw\t%0", + "fcom%z1\t%y1", + "fcomp%z1\t%y1", + "fucom%z1\t%y1", + "fucomp%z1\t%y1", - "ficom%z2\t%y2\n\tfnstsw\t%0", - "ficomp%z2\t%y2\n\tfnstsw\t%0", + "ficom%z1\t%y1", + "ficomp%z1\t%y1", NULL, NULL, @@ -8834,6 +8244,16 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) NULL, NULL, NULL, + NULL, + + "fcom%z2\t%y2\n\tfnstsw\t%0", + "fcomp%z2\t%y2\n\tfnstsw\t%0", + "fucom%z2\t%y2\n\tfnstsw\t%0", + "fucomp%z2\t%y2\n\tfnstsw\t%0", + + "ficom%z2\t%y2\n\tfnstsw\t%0", + "ficomp%z2\t%y2\n\tfnstsw\t%0", + NULL, NULL }; @@ -8841,13 +8261,15 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) const char *ret; mask = eflags_p << 3; - mask |= (GET_MODE_CLASS (GET_MODE (cmp_op1)) == MODE_INT) << 2; + mask |= (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT) << 2; mask |= unordered_p << 1; mask |= stack_top_dies; - gcc_assert (mask < 16); + if (mask >= 24) + abort (); ret = alt[mask]; - gcc_assert (ret); + if (ret == NULL) + abort (); return ret; } @@ -8858,12 +8280,14 @@ ix86_output_addr_vec_elt (FILE *file, int value) { const char *directive = ASM_LONG; -#ifdef ASM_QUAD if (TARGET_64BIT) - directive = ASM_QUAD; + { +#ifdef ASM_QUAD + directive = ASM_QUAD; #else - gcc_assert (!TARGET_64BIT); + abort (); #endif + } fprintf (file, "%s%s%d\n", directive, LPREFIX, value); } @@ -8898,7 +8322,8 @@ ix86_expand_clear (rtx dest) rtx tmp; /* We play register width games, which are only valid after reload. */ - gcc_assert (reload_completed); + if (!reload_completed) + abort (); /* Avoid HImode and its attendant prefix byte. */ if (GET_MODE_SIZE (GET_MODE (dest)) < 4) @@ -8919,7 +8344,7 @@ ix86_expand_clear (rtx dest) /* X is an unchanging MEM. If it is a constant pool reference, return the constant pool rtx, else NULL. */ -rtx +static rtx maybe_get_pool_constant (rtx x) { x = ix86_delegitimize_address (XEXP (x, 0)); @@ -8940,62 +8365,46 @@ ix86_expand_move (enum machine_mode mode, rtx operands[]) op0 = operands[0]; op1 = operands[1]; - if (GET_CODE (op1) == SYMBOL_REF) - { - model = SYMBOL_REF_TLS_MODEL (op1); - if (model) - { - op1 = legitimize_tls_address (op1, model, true); - op1 = force_operand (op1, op0); - if (op1 == op0) - return; - } - } - else if (GET_CODE (op1) == CONST - && GET_CODE (XEXP (op1, 0)) == PLUS - && GET_CODE (XEXP (XEXP (op1, 0), 0)) == SYMBOL_REF) + model = tls_symbolic_operand (op1, Pmode); + if (model) { - model = SYMBOL_REF_TLS_MODEL (XEXP (XEXP (op1, 0), 0)); - if (model) - { - rtx addend = XEXP (XEXP (op1, 0), 1); - op1 = legitimize_tls_address (XEXP (XEXP (op1, 0), 0), model, true); - op1 = force_operand (op1, NULL); - op1 = expand_simple_binop (Pmode, PLUS, op1, addend, - op0, 1, OPTAB_DIRECT); - if (op1 == op0) - return; - } + op1 = legitimize_tls_address (op1, model, true); + op1 = force_operand (op1, op0); + if (op1 == op0) + return; } if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode)) { - if (TARGET_MACHO && !TARGET_64BIT) - { #if TARGET_MACHO - if (MACHOPIC_PURE) - { - rtx temp = ((reload_in_progress - || ((op0 && GET_CODE (op0) == REG) - && mode == Pmode)) - ? op0 : gen_reg_rtx (Pmode)); - op1 = machopic_indirect_data_reference (op1, temp); - op1 = machopic_legitimize_pic_address (op1, mode, - temp == op1 ? 0 : temp); - } - else if (MACHOPIC_INDIRECT) - op1 = machopic_indirect_data_reference (op1, 0); - if (op0 == op1) - return; -#endif - } + if (MACHOPIC_PURE) + { + rtx temp = ((reload_in_progress + || ((op0 && GET_CODE (op0) == REG) + && mode == Pmode)) + ? op0 : gen_reg_rtx (Pmode)); + op1 = machopic_indirect_data_reference (op1, temp); + op1 = machopic_legitimize_pic_address (op1, mode, + temp == op1 ? 0 : temp); + } + else if (MACHOPIC_INDIRECT) + op1 = machopic_indirect_data_reference (op1, 0); + if (op0 == op1) + return; +#else + if (GET_CODE (op0) == MEM) + op1 = force_reg (Pmode, op1); else { - if (GET_CODE (op0) == MEM) - op1 = force_reg (Pmode, op1); - else - op1 = legitimize_address (op1, op1, Pmode); + rtx temp = op0; + if (GET_CODE (temp) != REG) + temp = gen_reg_rtx (Pmode); + temp = legitimize_pic_address (op1, temp); + if (temp == op0) + return; + op1 = temp; } +#endif /* TARGET_MACHO */ } else { @@ -9013,7 +8422,7 @@ ix86_expand_move (enum machine_mode mode, rtx operands[]) to get them CSEed. */ if (TARGET_64BIT && mode == DImode && immediate_operand (op1, mode) - && !x86_64_zext_immediate_operand (op1, VOIDmode) + && !x86_64_zero_extended_value (op1) && !register_operand (op0, mode) && optimize && !reload_completed && !reload_in_progress) op1 = copy_to_mode_reg (mode, op1); @@ -9046,186 +8455,45 @@ ix86_expand_move (enum machine_mode mode, rtx operands[]) void ix86_expand_vector_move (enum machine_mode mode, rtx operands[]) { - rtx op0 = operands[0], op1 = operands[1]; - /* Force constants other than zero into memory. We do not know how the instructions used to build constants modify the upper 64 bits of the register, once we have that information we may be able to handle some of them more efficiently. */ if ((reload_in_progress | reload_completed) == 0 - && register_operand (op0, mode) - && CONSTANT_P (op1) - && standard_sse_constant_p (op1) <= 0) - op1 = validize_mem (force_const_mem (mode, op1)); + && register_operand (operands[0], mode) + && CONSTANT_P (operands[1]) && operands[1] != CONST0_RTX (mode)) + operands[1] = validize_mem (force_const_mem (mode, operands[1])); /* Make operand1 a register if it isn't already. */ if (!no_new_pseudos - && !register_operand (op0, mode) - && !register_operand (op1, mode)) + && !register_operand (operands[0], mode) + && !register_operand (operands[1], mode)) { - emit_move_insn (op0, force_reg (GET_MODE (op0), op1)); + rtx temp = force_reg (GET_MODE (operands[1]), operands[1]); + emit_move_insn (operands[0], temp); return; } - emit_insn (gen_rtx_SET (VOIDmode, op0, op1)); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1])); } -/* Implement the movmisalign patterns for SSE. Non-SSE modes go - straight to ix86_expand_vector_move. */ - -void -ix86_expand_vector_move_misalign (enum machine_mode mode, rtx operands[]) -{ - rtx op0, op1, m; - - op0 = operands[0]; - op1 = operands[1]; - - if (MEM_P (op1)) - { - /* If we're optimizing for size, movups is the smallest. */ - if (optimize_size) - { - op0 = gen_lowpart (V4SFmode, op0); - op1 = gen_lowpart (V4SFmode, op1); - emit_insn (gen_sse_movups (op0, op1)); - return; - } - - /* ??? If we have typed data, then it would appear that using - movdqu is the only way to get unaligned data loaded with - integer type. */ - if (TARGET_SSE2 && GET_MODE_CLASS (mode) == MODE_VECTOR_INT) - { - op0 = gen_lowpart (V16QImode, op0); - op1 = gen_lowpart (V16QImode, op1); - emit_insn (gen_sse2_movdqu (op0, op1)); - return; - } - - if (TARGET_SSE2 && mode == V2DFmode) - { - rtx zero; - - /* When SSE registers are split into halves, we can avoid - writing to the top half twice. */ - if (TARGET_SSE_SPLIT_REGS) - { - emit_insn (gen_rtx_CLOBBER (VOIDmode, op0)); - zero = op0; - } - else - { - /* ??? Not sure about the best option for the Intel chips. - The following would seem to satisfy; the register is - entirely cleared, breaking the dependency chain. We - then store to the upper half, with a dependency depth - of one. A rumor has it that Intel recommends two movsd - followed by an unpacklpd, but this is unconfirmed. And - given that the dependency depth of the unpacklpd would - still be one, I'm not sure why this would be better. */ - zero = CONST0_RTX (V2DFmode); - } - - m = adjust_address (op1, DFmode, 0); - emit_insn (gen_sse2_loadlpd (op0, zero, m)); - m = adjust_address (op1, DFmode, 8); - emit_insn (gen_sse2_loadhpd (op0, op0, m)); - } - else - { - if (TARGET_SSE_PARTIAL_REG_DEPENDENCY) - emit_move_insn (op0, CONST0_RTX (mode)); - else - emit_insn (gen_rtx_CLOBBER (VOIDmode, op0)); - - if (mode != V4SFmode) - op0 = gen_lowpart (V4SFmode, op0); - m = adjust_address (op1, V2SFmode, 0); - emit_insn (gen_sse_loadlps (op0, op0, m)); - m = adjust_address (op1, V2SFmode, 8); - emit_insn (gen_sse_loadhps (op0, op0, m)); - } - } - else if (MEM_P (op0)) - { - /* If we're optimizing for size, movups is the smallest. */ - if (optimize_size) - { - op0 = gen_lowpart (V4SFmode, op0); - op1 = gen_lowpart (V4SFmode, op1); - emit_insn (gen_sse_movups (op0, op1)); - return; - } - - /* ??? Similar to above, only less clear because of quote - typeless stores unquote. */ - if (TARGET_SSE2 && !TARGET_SSE_TYPELESS_STORES - && GET_MODE_CLASS (mode) == MODE_VECTOR_INT) - { - op0 = gen_lowpart (V16QImode, op0); - op1 = gen_lowpart (V16QImode, op1); - emit_insn (gen_sse2_movdqu (op0, op1)); - return; - } - - if (TARGET_SSE2 && mode == V2DFmode) - { - m = adjust_address (op0, DFmode, 0); - emit_insn (gen_sse2_storelpd (m, op1)); - m = adjust_address (op0, DFmode, 8); - emit_insn (gen_sse2_storehpd (m, op1)); - } - else - { - if (mode != V4SFmode) - op1 = gen_lowpart (V4SFmode, op1); - m = adjust_address (op0, V2SFmode, 0); - emit_insn (gen_sse_storelps (m, op1)); - m = adjust_address (op0, V2SFmode, 8); - emit_insn (gen_sse_storehps (m, op1)); - } - } - else - gcc_unreachable (); -} - -/* Expand a push in MODE. This is some mode for which we do not support - proper push instructions, at least from the registers that we expect - the value to live in. */ +/* Attempt to expand a binary operator. Make the expansion closer to the + actual machine, then just general_operand, which will allow 3 separate + memory references (one output, two input) in a single insn. */ void -ix86_expand_push (enum machine_mode mode, rtx x) -{ - rtx tmp; - - tmp = expand_simple_binop (Pmode, PLUS, stack_pointer_rtx, - GEN_INT (-GET_MODE_SIZE (mode)), - stack_pointer_rtx, 1, OPTAB_DIRECT); - if (tmp != stack_pointer_rtx) - emit_move_insn (stack_pointer_rtx, tmp); - - tmp = gen_rtx_MEM (mode, stack_pointer_rtx); - emit_move_insn (tmp, x); -} - -/* Fix up OPERANDS to satisfy ix86_binary_operator_ok. Return the - destination to use for the operation. If different from the true - destination in operands[0], a copy operation will be required. */ - -rtx -ix86_fixup_binary_operands (enum rtx_code code, enum machine_mode mode, - rtx operands[]) +ix86_expand_binary_operator (enum rtx_code code, enum machine_mode mode, + rtx operands[]) { int matching_memory; - rtx src1, src2, dst; + rtx src1, src2, dst, op, clob; dst = operands[0]; src1 = operands[1]; src2 = operands[2]; /* Recognize <var1> = <value> <op> <var1> for commutative operators */ - if (GET_RTX_CLASS (code) == RTX_COMM_ARITH + if (GET_RTX_CLASS (code) == 'c' && (rtx_equal_p (dst, src2) || immediate_operand (src1, mode))) { @@ -9241,7 +8509,7 @@ ix86_fixup_binary_operands (enum rtx_code code, enum machine_mode mode, { if (rtx_equal_p (dst, src1)) matching_memory = 1; - else if (GET_RTX_CLASS (code) == RTX_COMM_ARITH + else if (GET_RTX_CLASS (code) == 'c' && rtx_equal_p (dst, src2)) matching_memory = 2; else @@ -9261,47 +8529,29 @@ ix86_fixup_binary_operands (enum rtx_code code, enum machine_mode mode, or non-matching memory. */ if ((CONSTANT_P (src1) || (!matching_memory && GET_CODE (src1) == MEM)) - && GET_RTX_CLASS (code) != RTX_COMM_ARITH) + && GET_RTX_CLASS (code) != 'c') src1 = force_reg (mode, src1); - src1 = operands[1] = src1; - src2 = operands[2] = src2; - return dst; -} - -/* Similarly, but assume that the destination has already been - set up properly. */ - -void -ix86_fixup_binary_operands_no_copy (enum rtx_code code, - enum machine_mode mode, rtx operands[]) -{ - rtx dst = ix86_fixup_binary_operands (code, mode, operands); - gcc_assert (dst == operands[0]); -} - -/* Attempt to expand a binary operator. Make the expansion closer to the - actual machine, then just general_operand, which will allow 3 separate - memory references (one output, two input) in a single insn. */ - -void -ix86_expand_binary_operator (enum rtx_code code, enum machine_mode mode, - rtx operands[]) -{ - rtx src1, src2, dst, op, clob; - - dst = ix86_fixup_binary_operands (code, mode, operands); - src1 = operands[1]; - src2 = operands[2]; + /* If optimizing, copy to regs to improve CSE */ + if (optimize && ! no_new_pseudos) + { + if (GET_CODE (dst) == MEM) + dst = gen_reg_rtx (mode); + if (GET_CODE (src1) == MEM) + src1 = force_reg (mode, src1); + if (GET_CODE (src2) == MEM) + src2 = force_reg (mode, src2); + } - /* Emit the instruction. */ + /* Emit the instruction. */ op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_ee (code, mode, src1, src2)); if (reload_in_progress) { /* Reload doesn't know about the flags register, and doesn't know that it doesn't want to clobber it. We can only do this with PLUS. */ - gcc_assert (code == PLUS); + if (code != PLUS) + abort (); emit_insn (op); } else @@ -9327,18 +8577,18 @@ ix86_binary_operator_ok (enum rtx_code code, if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[2]) == MEM) return 0; /* If the operation is not commutable, source 1 cannot be a constant. */ - if (CONSTANT_P (operands[1]) && GET_RTX_CLASS (code) != RTX_COMM_ARITH) + if (CONSTANT_P (operands[1]) && GET_RTX_CLASS (code) != 'c') return 0; /* If the destination is memory, we must have a matching source operand. */ if (GET_CODE (operands[0]) == MEM && ! (rtx_equal_p (operands[0], operands[1]) - || (GET_RTX_CLASS (code) == RTX_COMM_ARITH + || (GET_RTX_CLASS (code) == 'c' && rtx_equal_p (operands[0], operands[2])))) return 0; /* If the operation is not commutable and the source 1 is memory, we must have a matching destination. */ if (GET_CODE (operands[1]) == MEM - && GET_RTX_CLASS (code) != RTX_COMM_ARITH + && GET_RTX_CLASS (code) != 'c' && ! rtx_equal_p (operands[0], operands[1])) return 0; return 1; @@ -9361,7 +8611,7 @@ ix86_expand_unary_operator (enum rtx_code code, enum machine_mode mode, /* If the destination is memory, and we do not have matching source operands, do things in registers. */ matching_memory = 0; - if (MEM_P (dst)) + if (GET_CODE (dst) == MEM) { if (rtx_equal_p (dst, src)) matching_memory = 1; @@ -9370,9 +8620,18 @@ ix86_expand_unary_operator (enum rtx_code code, enum machine_mode mode, } /* When source operand is memory, destination must match. */ - if (MEM_P (src) && !matching_memory) + if (!matching_memory && GET_CODE (src) == MEM) src = force_reg (mode, src); + /* If optimizing, copy to regs to improve CSE */ + if (optimize && ! no_new_pseudos) + { + if (GET_CODE (dst) == MEM) + dst = gen_reg_rtx (mode); + if (GET_CODE (src) == MEM) + src = force_reg (mode, src); + } + /* Emit the instruction. */ op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_e (code, mode, src)); @@ -9380,7 +8639,8 @@ ix86_expand_unary_operator (enum rtx_code code, enum machine_mode mode, { /* Reload doesn't know about the flags register, and doesn't know that it doesn't want to clobber it. */ - gcc_assert (code == NOT); + if (code != NOT) + abort (); emit_insn (op); } else @@ -9410,278 +8670,6 @@ ix86_unary_operator_ok (enum rtx_code code ATTRIBUTE_UNUSED, return TRUE; } -/* A subroutine of ix86_expand_fp_absneg_operator and copysign expanders. - Create a mask for the sign bit in MODE for an SSE register. If VECT is - true, then replicate the mask for all elements of the vector register. - If INVERT is true, then create a mask excluding the sign bit. */ - -rtx -ix86_build_signbit_mask (enum machine_mode mode, bool vect, bool invert) -{ - enum machine_mode vec_mode; - HOST_WIDE_INT hi, lo; - int shift = 63; - rtvec v; - rtx mask; - - /* Find the sign bit, sign extended to 2*HWI. */ - if (mode == SFmode) - lo = 0x80000000, hi = lo < 0; - else if (HOST_BITS_PER_WIDE_INT >= 64) - lo = (HOST_WIDE_INT)1 << shift, hi = -1; - else - lo = 0, hi = (HOST_WIDE_INT)1 << (shift - HOST_BITS_PER_WIDE_INT); - - if (invert) - lo = ~lo, hi = ~hi; - - /* Force this value into the low part of a fp vector constant. */ - mask = immed_double_const (lo, hi, mode == SFmode ? SImode : DImode); - mask = gen_lowpart (mode, mask); - - if (mode == SFmode) - { - if (vect) - v = gen_rtvec (4, mask, mask, mask, mask); - else - v = gen_rtvec (4, mask, CONST0_RTX (SFmode), - CONST0_RTX (SFmode), CONST0_RTX (SFmode)); - vec_mode = V4SFmode; - } - else - { - if (vect) - v = gen_rtvec (2, mask, mask); - else - v = gen_rtvec (2, mask, CONST0_RTX (DFmode)); - vec_mode = V2DFmode; - } - - return force_reg (vec_mode, gen_rtx_CONST_VECTOR (vec_mode, v)); -} - -/* Generate code for floating point ABS or NEG. */ - -void -ix86_expand_fp_absneg_operator (enum rtx_code code, enum machine_mode mode, - rtx operands[]) -{ - rtx mask, set, use, clob, dst, src; - bool matching_memory; - bool use_sse = false; - bool vector_mode = VECTOR_MODE_P (mode); - enum machine_mode elt_mode = mode; - - if (vector_mode) - { - elt_mode = GET_MODE_INNER (mode); - use_sse = true; - } - else if (TARGET_SSE_MATH) - use_sse = SSE_FLOAT_MODE_P (mode); - - /* NEG and ABS performed with SSE use bitwise mask operations. - Create the appropriate mask now. */ - if (use_sse) - mask = ix86_build_signbit_mask (elt_mode, vector_mode, code == ABS); - else - mask = NULL_RTX; - - dst = operands[0]; - src = operands[1]; - - /* If the destination is memory, and we don't have matching source - operands or we're using the x87, do things in registers. */ - matching_memory = false; - if (MEM_P (dst)) - { - if (use_sse && rtx_equal_p (dst, src)) - matching_memory = true; - else - dst = gen_reg_rtx (mode); - } - if (MEM_P (src) && !matching_memory) - src = force_reg (mode, src); - - if (vector_mode) - { - set = gen_rtx_fmt_ee (code == NEG ? XOR : AND, mode, src, mask); - set = gen_rtx_SET (VOIDmode, dst, set); - emit_insn (set); - } - else - { - set = gen_rtx_fmt_e (code, mode, src); - set = gen_rtx_SET (VOIDmode, dst, set); - if (mask) - { - use = gen_rtx_USE (VOIDmode, mask); - clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); - emit_insn (gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (3, set, use, clob))); - } - else - emit_insn (set); - } - - if (dst != operands[0]) - emit_move_insn (operands[0], dst); -} - -/* Expand a copysign operation. Special case operand 0 being a constant. */ - -void -ix86_expand_copysign (rtx operands[]) -{ - enum machine_mode mode, vmode; - rtx dest, op0, op1, mask, nmask; - - dest = operands[0]; - op0 = operands[1]; - op1 = operands[2]; - - mode = GET_MODE (dest); - vmode = mode == SFmode ? V4SFmode : V2DFmode; - - if (GET_CODE (op0) == CONST_DOUBLE) - { - rtvec v; - - if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0))) - op0 = simplify_unary_operation (ABS, mode, op0, mode); - - if (op0 == CONST0_RTX (mode)) - op0 = CONST0_RTX (vmode); - else - { - if (mode == SFmode) - v = gen_rtvec (4, op0, CONST0_RTX (SFmode), - CONST0_RTX (SFmode), CONST0_RTX (SFmode)); - else - v = gen_rtvec (2, op0, CONST0_RTX (DFmode)); - op0 = force_reg (vmode, gen_rtx_CONST_VECTOR (vmode, v)); - } - - mask = ix86_build_signbit_mask (mode, 0, 0); - - if (mode == SFmode) - emit_insn (gen_copysignsf3_const (dest, op0, op1, mask)); - else - emit_insn (gen_copysigndf3_const (dest, op0, op1, mask)); - } - else - { - nmask = ix86_build_signbit_mask (mode, 0, 1); - mask = ix86_build_signbit_mask (mode, 0, 0); - - if (mode == SFmode) - emit_insn (gen_copysignsf3_var (dest, NULL, op0, op1, nmask, mask)); - else - emit_insn (gen_copysigndf3_var (dest, NULL, op0, op1, nmask, mask)); - } -} - -/* Deconstruct a copysign operation into bit masks. Operand 0 is known to - be a constant, and so has already been expanded into a vector constant. */ - -void -ix86_split_copysign_const (rtx operands[]) -{ - enum machine_mode mode, vmode; - rtx dest, op0, op1, mask, x; - - dest = operands[0]; - op0 = operands[1]; - op1 = operands[2]; - mask = operands[3]; - - mode = GET_MODE (dest); - vmode = GET_MODE (mask); - - dest = simplify_gen_subreg (vmode, dest, mode, 0); - x = gen_rtx_AND (vmode, dest, mask); - emit_insn (gen_rtx_SET (VOIDmode, dest, x)); - - if (op0 != CONST0_RTX (vmode)) - { - x = gen_rtx_IOR (vmode, dest, op0); - emit_insn (gen_rtx_SET (VOIDmode, dest, x)); - } -} - -/* Deconstruct a copysign operation into bit masks. Operand 0 is variable, - so we have to do two masks. */ - -void -ix86_split_copysign_var (rtx operands[]) -{ - enum machine_mode mode, vmode; - rtx dest, scratch, op0, op1, mask, nmask, x; - - dest = operands[0]; - scratch = operands[1]; - op0 = operands[2]; - op1 = operands[3]; - nmask = operands[4]; - mask = operands[5]; - - mode = GET_MODE (dest); - vmode = GET_MODE (mask); - - if (rtx_equal_p (op0, op1)) - { - /* Shouldn't happen often (it's useless, obviously), but when it does - we'd generate incorrect code if we continue below. */ - emit_move_insn (dest, op0); - return; - } - - if (REG_P (mask) && REGNO (dest) == REGNO (mask)) /* alternative 0 */ - { - gcc_assert (REGNO (op1) == REGNO (scratch)); - - x = gen_rtx_AND (vmode, scratch, mask); - emit_insn (gen_rtx_SET (VOIDmode, scratch, x)); - - dest = mask; - op0 = simplify_gen_subreg (vmode, op0, mode, 0); - x = gen_rtx_NOT (vmode, dest); - x = gen_rtx_AND (vmode, x, op0); - emit_insn (gen_rtx_SET (VOIDmode, dest, x)); - } - else - { - if (REGNO (op1) == REGNO (scratch)) /* alternative 1,3 */ - { - x = gen_rtx_AND (vmode, scratch, mask); - } - else /* alternative 2,4 */ - { - gcc_assert (REGNO (mask) == REGNO (scratch)); - op1 = simplify_gen_subreg (vmode, op1, mode, 0); - x = gen_rtx_AND (vmode, scratch, op1); - } - emit_insn (gen_rtx_SET (VOIDmode, scratch, x)); - - if (REGNO (op0) == REGNO (dest)) /* alternative 1,2 */ - { - dest = simplify_gen_subreg (vmode, op0, mode, 0); - x = gen_rtx_AND (vmode, dest, nmask); - } - else /* alternative 3,4 */ - { - gcc_assert (REGNO (nmask) == REGNO (dest)); - dest = nmask; - op0 = simplify_gen_subreg (vmode, op0, mode, 0); - x = gen_rtx_AND (vmode, dest, op0); - } - emit_insn (gen_rtx_SET (VOIDmode, dest, x)); - } - - x = gen_rtx_IOR (vmode, dest, scratch); - emit_insn (gen_rtx_SET (VOIDmode, dest, x)); -} - /* Return TRUE or FALSE depending on whether the first SET in INSN has source and destination with matching CC modes, and that the CC mode is at least as constrained as REQ_MODE. */ @@ -9695,8 +8683,10 @@ ix86_match_ccmode (rtx insn, enum machine_mode req_mode) set = PATTERN (insn); if (GET_CODE (set) == PARALLEL) set = XVECEXP (set, 0, 0); - gcc_assert (GET_CODE (set) == SET); - gcc_assert (GET_CODE (SET_SRC (set)) == COMPARE); + if (GET_CODE (set) != SET) + abort (); + if (GET_CODE (SET_SRC (set)) != COMPARE) + abort (); set_mode = GET_MODE (SET_DEST (set)); switch (set_mode) @@ -9723,7 +8713,7 @@ ix86_match_ccmode (rtx insn, enum machine_mode req_mode) break; default: - gcc_unreachable (); + abort (); } return (GET_MODE (SET_SRC (set)) == set_mode); @@ -9767,7 +8757,7 @@ ix86_fp_compare_mode (enum rtx_code code ATTRIBUTE_UNUSED) enum machine_mode ix86_cc_mode (enum rtx_code code, rtx op0, rtx op1) { - if (SCALAR_FLOAT_MODE_P (GET_MODE (op0))) + if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT) return ix86_fp_compare_mode (code); switch (code) { @@ -9805,7 +8795,7 @@ ix86_cc_mode (enum rtx_code code, rtx op0, rtx op1) case USE: return CCmode; default: - gcc_unreachable (); + abort (); } } @@ -9839,7 +8829,7 @@ ix86_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2) switch (m1) { default: - gcc_unreachable (); + abort (); case CCmode: case CCGCmode: @@ -9888,20 +8878,15 @@ ix86_prepare_fp_compare_args (enum rtx_code code, rtx *pop0, rtx *pop1) enum machine_mode fpcmp_mode = ix86_fp_compare_mode (code); rtx op0 = *pop0, op1 = *pop1; enum machine_mode op_mode = GET_MODE (op0); - int is_sse = TARGET_SSE_MATH && SSE_FLOAT_MODE_P (op_mode); + int is_sse = SSE_REG_P (op0) | SSE_REG_P (op1); /* All of the unordered compare instructions only work on registers. - The same is true of the fcomi compare instructions. The XFmode - compare instructions require registers except when comparing - against zero or when converting operand 1 from fixed point to - floating point. */ + The same is true of the XFmode compare instructions. The same is + true of the fcomi compare instructions. */ if (!is_sse && (fpcmp_mode == CCFPUmode - || (op_mode == XFmode - && ! (standard_80387_constant_p (op0) == 1 - || standard_80387_constant_p (op1) == 1) - && GET_CODE (op1) != FLOAT) + || op_mode == XFmode || ix86_use_fcomi_compare (code))) { op0 = force_reg (op_mode, op0); @@ -9928,16 +8913,10 @@ ix86_prepare_fp_compare_args (enum rtx_code code, rtx *pop0, rtx *pop1) if (CONSTANT_P (op1)) { - int tmp = standard_80387_constant_p (op1); - if (tmp == 0) - op1 = validize_mem (force_const_mem (op_mode, op1)); - else if (tmp == 1) - { - if (TARGET_CMOVE) - op1 = force_reg (op_mode, op1); - } - else + if (standard_80387_constant_p (op1)) op1 = force_reg (op_mode, op1); + else + op1 = validize_mem (force_const_mem (op_mode, op1)); } } @@ -9961,8 +8940,7 @@ ix86_prepare_fp_compare_args (enum rtx_code code, rtx *pop0, rtx *pop1) /* Convert comparison codes we use to represent FP comparison to integer code that will result in proper branch. Return UNKNOWN if no such code is available. */ - -enum rtx_code +static enum rtx_code ix86_fp_compare_code_to_integer (enum rtx_code code) { switch (code) @@ -9995,17 +8973,16 @@ ix86_fp_compare_code_to_integer (enum rtx_code code) /* Split comparison code CODE into comparisons we can do using branch instructions. BYPASS_CODE is comparison code for branch that will branch around FIRST_CODE and SECOND_CODE. If some of branches - is not required, set value to UNKNOWN. + is not required, set value to NIL. We never require more than two branches. */ - -void +static void ix86_fp_comparison_codes (enum rtx_code code, enum rtx_code *bypass_code, enum rtx_code *first_code, enum rtx_code *second_code) { *first_code = code; - *bypass_code = UNKNOWN; - *second_code = UNKNOWN; + *bypass_code = NIL; + *second_code = NIL; /* The fcomi comparison sets flags as follows: @@ -10051,12 +9028,12 @@ ix86_fp_comparison_codes (enum rtx_code code, enum rtx_code *bypass_code, *second_code = UNORDERED; break; default: - gcc_unreachable (); + abort (); } if (!TARGET_IEEE_FP) { - *second_code = UNKNOWN; - *bypass_code = UNKNOWN; + *second_code = NIL; + *bypass_code = NIL; } } @@ -10093,7 +9070,7 @@ ix86_fp_comparison_arithmetics_cost (enum rtx_code code) return 6; break; default: - gcc_unreachable (); + abort (); } } @@ -10108,7 +9085,7 @@ ix86_fp_comparison_fcomi_cost (enum rtx_code code) if (!TARGET_CMOVE) return 1024; ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code); - return (bypass_code != UNKNOWN || second_code != UNKNOWN) + 2; + return (bypass_code != NIL || second_code != NIL) + 2; } /* Return cost of comparison done using sahf operation. @@ -10122,7 +9099,7 @@ ix86_fp_comparison_sahf_cost (enum rtx_code code) if (!TARGET_USE_SAHF && !optimize_size) return 1024; ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code); - return (bypass_code != UNKNOWN || second_code != UNKNOWN) + 3; + return (bypass_code != NIL || second_code != NIL) + 3; } /* Compute cost of the comparison done using any method. @@ -10166,8 +9143,8 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch, ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code); /* Do fcomi/sahf based test when profitable. */ - if ((bypass_code == UNKNOWN || bypass_test) - && (second_code == UNKNOWN || second_test) + if ((bypass_code == NIL || bypass_test) + && (second_code == NIL || second_test) && ix86_fp_comparison_arithmetics_cost (code) > cost) { if (TARGET_CMOVE) @@ -10190,11 +9167,11 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch, /* The FP codes work out to act like unsigned. */ intcmp_mode = fpcmp_mode; code = first_code; - if (bypass_code != UNKNOWN) + if (bypass_code != NIL) *bypass_test = gen_rtx_fmt_ee (bypass_code, VOIDmode, gen_rtx_REG (intcmp_mode, FLAGS_REG), const0_rtx); - if (second_code != UNKNOWN) + if (second_code != NIL) *second_test = gen_rtx_fmt_ee (second_code, VOIDmode, gen_rtx_REG (intcmp_mode, FLAGS_REG), const0_rtx); @@ -10320,7 +9297,7 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch, break; default: - gcc_unreachable (); + abort (); } } @@ -10343,12 +9320,7 @@ ix86_expand_compare (enum rtx_code code, rtx *second_test, rtx *bypass_test) if (bypass_test) *bypass_test = NULL_RTX; - if (ix86_compare_emitted) - { - ret = gen_rtx_fmt_ee (code, VOIDmode, ix86_compare_emitted, const0_rtx); - ix86_compare_emitted = NULL_RTX; - } - else if (SCALAR_FLOAT_MODE_P (GET_MODE (op0))) + if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT) ret = ix86_expand_fp_compare (code, op0, op1, NULL_RTX, second_test, bypass_test); else @@ -10365,7 +9337,7 @@ ix86_fp_jump_nontrivial_p (enum rtx_code code) if (!TARGET_CMOVE) return true; ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code); - return bypass_code != UNKNOWN || second_code != UNKNOWN; + return bypass_code != NIL || second_code != NIL; } void @@ -10373,12 +9345,6 @@ ix86_expand_branch (enum rtx_code code, rtx label) { rtx tmp; - /* If we have emitted a compare insn, go straight to simple. - ix86_expand_compare won't emit anything if ix86_compare_emitted - is non NULL. */ - if (ix86_compare_emitted) - goto simple; - switch (GET_MODE (ix86_compare_op0)) { case QImode: @@ -10408,12 +9374,12 @@ ix86_expand_branch (enum rtx_code code, rtx label) /* Check whether we will use the natural sequence with one jump. If so, we can expand jump early. Otherwise delay expansion by creating compound insn to not confuse optimizers. */ - if (bypass_code == UNKNOWN && second_code == UNKNOWN + if (bypass_code == NIL && second_code == NIL && TARGET_CMOVE) { ix86_split_fp_branch (code, ix86_compare_op0, ix86_compare_op1, gen_rtx_LABEL_REF (VOIDmode, label), - pc_rtx, NULL_RTX, NULL_RTX); + pc_rtx, NULL_RTX); } else { @@ -10443,12 +9409,10 @@ ix86_expand_branch (enum rtx_code code, rtx label) case DImode: if (TARGET_64BIT) goto simple; - case TImode: /* Expand DImode branch into multiple compare+branch. */ { rtx lo[2], hi[2], label2; enum rtx_code code1, code2, code3; - enum machine_mode submode; if (CONSTANT_P (ix86_compare_op0) && ! CONSTANT_P (ix86_compare_op1)) { @@ -10457,18 +9421,8 @@ ix86_expand_branch (enum rtx_code code, rtx label) ix86_compare_op1 = tmp; code = swap_condition (code); } - if (GET_MODE (ix86_compare_op0) == DImode) - { - split_di (&ix86_compare_op0, 1, lo+0, hi+0); - split_di (&ix86_compare_op1, 1, lo+1, hi+1); - submode = SImode; - } - else - { - split_ti (&ix86_compare_op0, 1, lo+0, hi+0); - split_ti (&ix86_compare_op1, 1, lo+1, hi+1); - submode = DImode; - } + split_di (&ix86_compare_op0, 1, lo+0, hi+0); + split_di (&ix86_compare_op1, 1, lo+1, hi+1); /* When comparing for equality, we can use (hi0^hi1)|(lo0^lo1) to avoid two branches. This costs one extra insn, so disable when @@ -10482,15 +9436,15 @@ ix86_expand_branch (enum rtx_code code, rtx label) xor1 = hi[0]; if (hi[1] != const0_rtx) - xor1 = expand_binop (submode, xor_optab, xor1, hi[1], + xor1 = expand_binop (SImode, xor_optab, xor1, hi[1], NULL_RTX, 0, OPTAB_WIDEN); xor0 = lo[0]; if (lo[1] != const0_rtx) - xor0 = expand_binop (submode, xor_optab, xor0, lo[1], + xor0 = expand_binop (SImode, xor_optab, xor0, lo[1], NULL_RTX, 0, OPTAB_WIDEN); - tmp = expand_binop (submode, ior_optab, xor1, xor0, + tmp = expand_binop (SImode, ior_optab, xor1, xor0, NULL_RTX, 0, OPTAB_WIDEN); ix86_compare_op0 = tmp; @@ -10533,11 +9487,11 @@ ix86_expand_branch (enum rtx_code code, rtx label) case LEU: code1 = LTU; code2 = GTU; break; case GEU: code1 = GTU; code2 = LTU; break; - case EQ: code1 = UNKNOWN; code2 = NE; break; - case NE: code2 = UNKNOWN; break; + case EQ: code1 = NIL; code2 = NE; break; + case NE: code2 = NIL; break; default: - gcc_unreachable (); + abort (); } /* @@ -10551,29 +9505,29 @@ ix86_expand_branch (enum rtx_code code, rtx label) ix86_compare_op0 = hi[0]; ix86_compare_op1 = hi[1]; - if (code1 != UNKNOWN) + if (code1 != NIL) ix86_expand_branch (code1, label); - if (code2 != UNKNOWN) + if (code2 != NIL) ix86_expand_branch (code2, label2); ix86_compare_op0 = lo[0]; ix86_compare_op1 = lo[1]; ix86_expand_branch (code3, label); - if (code2 != UNKNOWN) + if (code2 != NIL) emit_label (label2); return; } default: - gcc_unreachable (); + abort (); } } /* Split branch based on floating point condition. */ void ix86_split_fp_branch (enum rtx_code code, rtx op1, rtx op2, - rtx target1, rtx target2, rtx tmp, rtx pushed) + rtx target1, rtx target2, rtx tmp) { rtx second, bypass; rtx label = NULL_RTX; @@ -10592,10 +9546,6 @@ ix86_split_fp_branch (enum rtx_code code, rtx op1, rtx op2, condition = ix86_expand_fp_compare (code, op1, op2, tmp, &second, &bypass); - /* Remove pushed operand from stack. */ - if (pushed) - ix86_free_from_memory (GET_MODE (pushed)); - if (split_branch_probability >= 0) { /* Distribute the probabilities across the jumps. @@ -10658,10 +9608,12 @@ ix86_expand_setcc (enum rtx_code code, rtx dest) rtx ret, tmp, tmpreg, equiv; rtx second_test, bypass_test; - if (GET_MODE (ix86_compare_op0) == (TARGET_64BIT ? TImode : DImode)) + if (GET_MODE (ix86_compare_op0) == DImode + && !TARGET_64BIT) return 0; /* FAIL */ - gcc_assert (GET_MODE (dest) == QImode); + if (GET_MODE (dest) != QImode) + abort (); ret = ix86_expand_compare (code, &second_test, &bypass_test); PUT_MODE (ret, QImode); @@ -10677,7 +9629,8 @@ ix86_expand_setcc (enum rtx_code code, rtx dest) rtx tmp2 = gen_reg_rtx (QImode); if (bypass_test) { - gcc_assert (!second_test); + if (second_test) + abort (); test = bypass_test; bypass = 1; PUT_CODE (test, reverse_condition_maybe_unordered (GET_CODE (test))); @@ -10692,13 +9645,10 @@ ix86_expand_setcc (enum rtx_code code, rtx dest) } /* Attach a REG_EQUAL note describing the comparison result. */ - if (ix86_compare_op0 && ix86_compare_op1) - { - equiv = simplify_gen_relational (code, QImode, - GET_MODE (ix86_compare_op0), - ix86_compare_op0, ix86_compare_op1); - set_unique_reg_note (get_last_insn (), REG_EQUAL, equiv); - } + equiv = simplify_gen_relational (code, QImode, + GET_MODE (ix86_compare_op0), + ix86_compare_op0, ix86_compare_op1); + set_unique_reg_note (get_last_insn (), REG_EQUAL, equiv); return 1; /* DONE */ } @@ -10711,9 +9661,9 @@ ix86_expand_carry_flag_compare (enum rtx_code code, rtx op0, rtx op1, rtx *pop) enum machine_mode mode = GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1); - /* Do not handle DImode compares that go through special path. Also we can't + /* Do not handle DImode compares that go trought special path. Also we can't deal with FP compares yet. This is possible to add. */ - if (mode == (TARGET_64BIT ? TImode : DImode)) + if ((mode == DImode && !TARGET_64BIT)) return false; if (FLOAT_MODE_P (mode)) { @@ -10825,7 +9775,8 @@ ix86_expand_carry_flag_compare (enum rtx_code code, rtx op0, rtx op1, rtx *pop) ix86_compare_op0 = op0; ix86_compare_op1 = op1; *pop = ix86_expand_compare (code, NULL, NULL); - gcc_assert (GET_CODE (*pop) == LTU || GET_CODE (*pop) == GEU); + if (GET_CODE (*pop) != LTU && GET_CODE (*pop) != GEU) + abort (); return true; } @@ -10853,7 +9804,7 @@ ix86_expand_int_movcc (rtx operands[]) HImode insns, we'd be swallowed in word prefix ops. */ if ((mode != HImode || TARGET_FAST_PREFIX) - && (mode != (TARGET_64BIT ? TImode : DImode)) + && (mode != DImode || TARGET_64BIT) && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[3]) == CONST_INT) { @@ -11028,7 +9979,7 @@ ix86_expand_int_movcc (rtx operands[]) } } - compare_code = UNKNOWN; + compare_code = NIL; if (GET_MODE_CLASS (GET_MODE (ix86_compare_op0)) == MODE_INT && GET_CODE (ix86_compare_op1) == CONST_INT) { @@ -11045,7 +9996,7 @@ ix86_expand_int_movcc (rtx operands[]) } /* Optimize dest = (op0 < 0) ? -1 : cf. */ - if (compare_code != UNKNOWN + if (compare_code != NIL && GET_MODE (ix86_compare_op0) == GET_MODE (out) && (cf == -1 || ct == -1)) { @@ -11086,8 +10037,7 @@ ix86_expand_int_movcc (rtx operands[]) if ((diff == 1 || diff == 2 || diff == 4 || diff == 8 || diff == 3 || diff == 5 || diff == 9) && ((mode != QImode && mode != HImode) || !TARGET_PARTIAL_REG_STALL) - && (mode != DImode - || x86_64_immediate_operand (GEN_INT (cf), VOIDmode))) + && (mode != DImode || x86_64_sign_extended_value (GEN_INT (cf)))) { /* * xorl dest,dest @@ -11173,12 +10123,12 @@ ix86_expand_int_movcc (rtx operands[]) else { code = reverse_condition (code); - if (compare_code != UNKNOWN) + if (compare_code != NIL) compare_code = reverse_condition (compare_code); } } - if (compare_code != UNKNOWN) + if (compare_code != NIL) { /* notl op1 (if needed) sarl $31, op1 @@ -11341,233 +10291,121 @@ ix86_expand_int_movcc (rtx operands[]) return 1; /* DONE */ } -/* Swap, force into registers, or otherwise massage the two operands - to an sse comparison with a mask result. Thus we differ a bit from - ix86_prepare_fp_compare_args which expects to produce a flags result. - - The DEST operand exists to help determine whether to commute commutative - operators. The POP0/POP1 operands are updated in place. The new - comparison code is returned, or UNKNOWN if not implementable. */ - -static enum rtx_code -ix86_prepare_sse_fp_compare_args (rtx dest, enum rtx_code code, - rtx *pop0, rtx *pop1) -{ - rtx tmp; - - switch (code) - { - case LTGT: - case UNEQ: - /* We have no LTGT as an operator. We could implement it with - NE & ORDERED, but this requires an extra temporary. It's - not clear that it's worth it. */ - return UNKNOWN; - - case LT: - case LE: - case UNGT: - case UNGE: - /* These are supported directly. */ - break; - - case EQ: - case NE: - case UNORDERED: - case ORDERED: - /* For commutative operators, try to canonicalize the destination - operand to be first in the comparison - this helps reload to - avoid extra moves. */ - if (!dest || !rtx_equal_p (dest, *pop1)) - break; - /* FALLTHRU */ - - case GE: - case GT: - case UNLE: - case UNLT: - /* These are not supported directly. Swap the comparison operands - to transform into something that is supported. */ - tmp = *pop0; - *pop0 = *pop1; - *pop1 = tmp; - code = swap_condition (code); - break; - - default: - gcc_unreachable (); - } - - return code; -} - -/* Detect conditional moves that exactly match min/max operational - semantics. Note that this is IEEE safe, as long as we don't - interchange the operands. - - Returns FALSE if this conditional move doesn't match a MIN/MAX, - and TRUE if the operation is successful and instructions are emitted. */ - -static bool -ix86_expand_sse_fp_minmax (rtx dest, enum rtx_code code, rtx cmp_op0, - rtx cmp_op1, rtx if_true, rtx if_false) -{ - enum machine_mode mode; - bool is_min; - rtx tmp; - - if (code == LT) - ; - else if (code == UNGE) - { - tmp = if_true; - if_true = if_false; - if_false = tmp; - } - else - return false; - - if (rtx_equal_p (cmp_op0, if_true) && rtx_equal_p (cmp_op1, if_false)) - is_min = true; - else if (rtx_equal_p (cmp_op1, if_true) && rtx_equal_p (cmp_op0, if_false)) - is_min = false; - else - return false; - - mode = GET_MODE (dest); - - /* We want to check HONOR_NANS and HONOR_SIGNED_ZEROS here, - but MODE may be a vector mode and thus not appropriate. */ - if (!flag_finite_math_only || !flag_unsafe_math_optimizations) - { - int u = is_min ? UNSPEC_IEEE_MIN : UNSPEC_IEEE_MAX; - rtvec v; - - if_true = force_reg (mode, if_true); - v = gen_rtvec (2, if_true, if_false); - tmp = gen_rtx_UNSPEC (mode, v, u); - } - else - { - code = is_min ? SMIN : SMAX; - tmp = gen_rtx_fmt_ee (code, mode, if_true, if_false); - } - - emit_insn (gen_rtx_SET (VOIDmode, dest, tmp)); - return true; -} - -/* Expand an sse vector comparison. Return the register with the result. */ - -static rtx -ix86_expand_sse_cmp (rtx dest, enum rtx_code code, rtx cmp_op0, rtx cmp_op1, - rtx op_true, rtx op_false) -{ - enum machine_mode mode = GET_MODE (dest); - rtx x; - - cmp_op0 = force_reg (mode, cmp_op0); - if (!nonimmediate_operand (cmp_op1, mode)) - cmp_op1 = force_reg (mode, cmp_op1); - - if (optimize - || reg_overlap_mentioned_p (dest, op_true) - || reg_overlap_mentioned_p (dest, op_false)) - dest = gen_reg_rtx (mode); - - x = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1); - emit_insn (gen_rtx_SET (VOIDmode, dest, x)); - - return dest; -} - -/* Expand DEST = CMP ? OP_TRUE : OP_FALSE into a sequence of logical - operations. This is used for both scalar and vector conditional moves. */ - -static void -ix86_expand_sse_movcc (rtx dest, rtx cmp, rtx op_true, rtx op_false) -{ - enum machine_mode mode = GET_MODE (dest); - rtx t2, t3, x; - - if (op_false == CONST0_RTX (mode)) - { - op_true = force_reg (mode, op_true); - x = gen_rtx_AND (mode, cmp, op_true); - emit_insn (gen_rtx_SET (VOIDmode, dest, x)); - } - else if (op_true == CONST0_RTX (mode)) - { - op_false = force_reg (mode, op_false); - x = gen_rtx_NOT (mode, cmp); - x = gen_rtx_AND (mode, x, op_false); - emit_insn (gen_rtx_SET (VOIDmode, dest, x)); - } - else - { - op_true = force_reg (mode, op_true); - op_false = force_reg (mode, op_false); - - t2 = gen_reg_rtx (mode); - if (optimize) - t3 = gen_reg_rtx (mode); - else - t3 = dest; - - x = gen_rtx_AND (mode, op_true, cmp); - emit_insn (gen_rtx_SET (VOIDmode, t2, x)); - - x = gen_rtx_NOT (mode, cmp); - x = gen_rtx_AND (mode, x, op_false); - emit_insn (gen_rtx_SET (VOIDmode, t3, x)); - - x = gen_rtx_IOR (mode, t3, t2); - emit_insn (gen_rtx_SET (VOIDmode, dest, x)); - } -} - -/* Expand a floating-point conditional move. Return true if successful. */ - int ix86_expand_fp_movcc (rtx operands[]) { - enum machine_mode mode = GET_MODE (operands[0]); - enum rtx_code code = GET_CODE (operands[1]); - rtx tmp, compare_op, second_test, bypass_test; - - if (TARGET_SSE_MATH && SSE_FLOAT_MODE_P (mode)) - { - enum machine_mode cmode; - - /* Since we've no cmove for sse registers, don't force bad register - allocation just to gain access to it. Deny movcc when the - comparison mode doesn't match the move mode. */ - cmode = GET_MODE (ix86_compare_op0); - if (cmode == VOIDmode) - cmode = GET_MODE (ix86_compare_op1); - if (cmode != mode) - return 0; - - code = ix86_prepare_sse_fp_compare_args (operands[0], code, - &ix86_compare_op0, - &ix86_compare_op1); - if (code == UNKNOWN) - return 0; - - if (ix86_expand_sse_fp_minmax (operands[0], code, ix86_compare_op0, - ix86_compare_op1, operands[2], - operands[3])) - return 1; - - tmp = ix86_expand_sse_cmp (operands[0], code, ix86_compare_op0, - ix86_compare_op1, operands[2], operands[3]); - ix86_expand_sse_movcc (operands[0], tmp, operands[2], operands[3]); + enum rtx_code code; + rtx tmp; + rtx compare_op, second_test, bypass_test; + + /* For SF/DFmode conditional moves based on comparisons + in same mode, we may want to use SSE min/max instructions. */ + if (((TARGET_SSE_MATH && GET_MODE (operands[0]) == SFmode) + || (TARGET_SSE2 && TARGET_SSE_MATH && GET_MODE (operands[0]) == DFmode)) + && GET_MODE (ix86_compare_op0) == GET_MODE (operands[0]) + /* The SSE comparisons does not support the LTGT/UNEQ pair. */ + && (!TARGET_IEEE_FP + || (GET_CODE (operands[1]) != LTGT && GET_CODE (operands[1]) != UNEQ)) + /* We may be called from the post-reload splitter. */ + && (!REG_P (operands[0]) + || SSE_REG_P (operands[0]) + || REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)) + { + rtx op0 = ix86_compare_op0, op1 = ix86_compare_op1; + code = GET_CODE (operands[1]); + + /* See if we have (cross) match between comparison operands and + conditional move operands. */ + if (rtx_equal_p (operands[2], op1)) + { + rtx tmp = op0; + op0 = op1; + op1 = tmp; + code = reverse_condition_maybe_unordered (code); + } + if (rtx_equal_p (operands[2], op0) && rtx_equal_p (operands[3], op1)) + { + /* Check for min operation. */ + if (code == LT || code == UNLE) + { + if (code == UNLE) + { + rtx tmp = op0; + op0 = op1; + op1 = tmp; + } + operands[0] = force_reg (GET_MODE (operands[0]), operands[0]); + if (memory_operand (op0, VOIDmode)) + op0 = force_reg (GET_MODE (operands[0]), op0); + if (GET_MODE (operands[0]) == SFmode) + emit_insn (gen_minsf3 (operands[0], op0, op1)); + else + emit_insn (gen_mindf3 (operands[0], op0, op1)); + return 1; + } + /* Check for max operation. */ + if (code == GT || code == UNGE) + { + if (code == UNGE) + { + rtx tmp = op0; + op0 = op1; + op1 = tmp; + } + operands[0] = force_reg (GET_MODE (operands[0]), operands[0]); + if (memory_operand (op0, VOIDmode)) + op0 = force_reg (GET_MODE (operands[0]), op0); + if (GET_MODE (operands[0]) == SFmode) + emit_insn (gen_maxsf3 (operands[0], op0, op1)); + else + emit_insn (gen_maxdf3 (operands[0], op0, op1)); + return 1; + } + } + /* Manage condition to be sse_comparison_operator. In case we are + in non-ieee mode, try to canonicalize the destination operand + to be first in the comparison - this helps reload to avoid extra + moves. */ + if (!sse_comparison_operator (operands[1], VOIDmode) + || (rtx_equal_p (operands[0], ix86_compare_op1) && !TARGET_IEEE_FP)) + { + rtx tmp = ix86_compare_op0; + ix86_compare_op0 = ix86_compare_op1; + ix86_compare_op1 = tmp; + operands[1] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[1])), + VOIDmode, ix86_compare_op0, + ix86_compare_op1); + } + /* Similarly try to manage result to be first operand of conditional + move. We also don't support the NE comparison on SSE, so try to + avoid it. */ + if ((rtx_equal_p (operands[0], operands[3]) + && (!TARGET_IEEE_FP || GET_CODE (operands[1]) != EQ)) + || (GET_CODE (operands[1]) == NE && TARGET_IEEE_FP)) + { + rtx tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + operands[1] = gen_rtx_fmt_ee (reverse_condition_maybe_unordered + (GET_CODE (operands[1])), + VOIDmode, ix86_compare_op0, + ix86_compare_op1); + } + if (GET_MODE (operands[0]) == SFmode) + emit_insn (gen_sse_movsfcc (operands[0], operands[1], + operands[2], operands[3], + ix86_compare_op0, ix86_compare_op1)); + else + emit_insn (gen_sse_movdfcc (operands[0], operands[1], + operands[2], operands[3], + ix86_compare_op0, ix86_compare_op1)); return 1; } /* The floating point conditional move instructions don't directly support conditions resulting from a signed integer comparison. */ + code = GET_CODE (operands[1]); compare_op = ix86_expand_compare (code, &second_test, &bypass_test); /* The floating point conditional move instructions don't directly @@ -11575,7 +10413,8 @@ ix86_expand_fp_movcc (rtx operands[]) if (!fcmov_comparison_operator (compare_op, VOIDmode)) { - gcc_assert (!second_test && !bypass_test); + if (second_test != NULL || bypass_test != NULL) + abort (); tmp = gen_reg_rtx (QImode); ix86_expand_setcc (code, tmp); code = NE; @@ -11585,160 +10424,38 @@ ix86_expand_fp_movcc (rtx operands[]) } if (bypass_test && reg_overlap_mentioned_p (operands[0], operands[3])) { - tmp = gen_reg_rtx (mode); + tmp = gen_reg_rtx (GET_MODE (operands[0])); emit_move_insn (tmp, operands[3]); operands[3] = tmp; } if (second_test && reg_overlap_mentioned_p (operands[0], operands[2])) { - tmp = gen_reg_rtx (mode); + tmp = gen_reg_rtx (GET_MODE (operands[0])); emit_move_insn (tmp, operands[2]); operands[2] = tmp; } emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_IF_THEN_ELSE (mode, compare_op, - operands[2], operands[3]))); + gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), + compare_op, + operands[2], + operands[3]))); if (bypass_test) emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_IF_THEN_ELSE (mode, bypass_test, - operands[3], operands[0]))); + gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), + bypass_test, + operands[3], + operands[0]))); if (second_test) emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_IF_THEN_ELSE (mode, second_test, - operands[2], operands[0]))); + gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), + second_test, + operands[2], + operands[0]))); return 1; } -/* Expand a floating-point vector conditional move; a vcond operation - rather than a movcc operation. */ - -bool -ix86_expand_fp_vcond (rtx operands[]) -{ - enum rtx_code code = GET_CODE (operands[3]); - rtx cmp; - - code = ix86_prepare_sse_fp_compare_args (operands[0], code, - &operands[4], &operands[5]); - if (code == UNKNOWN) - return false; - - if (ix86_expand_sse_fp_minmax (operands[0], code, operands[4], - operands[5], operands[1], operands[2])) - return true; - - cmp = ix86_expand_sse_cmp (operands[0], code, operands[4], operands[5], - operands[1], operands[2]); - ix86_expand_sse_movcc (operands[0], cmp, operands[1], operands[2]); - return true; -} - -/* Expand a signed integral vector conditional move. */ - -bool -ix86_expand_int_vcond (rtx operands[]) -{ - enum machine_mode mode = GET_MODE (operands[0]); - enum rtx_code code = GET_CODE (operands[3]); - bool negate = false; - rtx x, cop0, cop1; - - cop0 = operands[4]; - cop1 = operands[5]; - - /* Canonicalize the comparison to EQ, GT, GTU. */ - switch (code) - { - case EQ: - case GT: - case GTU: - break; - - case NE: - case LE: - case LEU: - code = reverse_condition (code); - negate = true; - break; - - case GE: - case GEU: - code = reverse_condition (code); - negate = true; - /* FALLTHRU */ - - case LT: - case LTU: - code = swap_condition (code); - x = cop0, cop0 = cop1, cop1 = x; - break; - - default: - gcc_unreachable (); - } - - /* Unsigned parallel compare is not supported by the hardware. Play some - tricks to turn this into a signed comparison against 0. */ - if (code == GTU) - { - cop0 = force_reg (mode, cop0); - - switch (mode) - { - case V4SImode: - { - rtx t1, t2, mask; - - /* Perform a parallel modulo subtraction. */ - t1 = gen_reg_rtx (mode); - emit_insn (gen_subv4si3 (t1, cop0, cop1)); - - /* Extract the original sign bit of op0. */ - mask = GEN_INT (-0x80000000); - mask = gen_rtx_CONST_VECTOR (mode, - gen_rtvec (4, mask, mask, mask, mask)); - mask = force_reg (mode, mask); - t2 = gen_reg_rtx (mode); - emit_insn (gen_andv4si3 (t2, cop0, mask)); - - /* XOR it back into the result of the subtraction. This results - in the sign bit set iff we saw unsigned underflow. */ - x = gen_reg_rtx (mode); - emit_insn (gen_xorv4si3 (x, t1, t2)); - - code = GT; - } - break; - - case V16QImode: - case V8HImode: - /* Perform a parallel unsigned saturating subtraction. */ - x = gen_reg_rtx (mode); - emit_insn (gen_rtx_SET (VOIDmode, x, - gen_rtx_US_MINUS (mode, cop0, cop1))); - - code = EQ; - negate = !negate; - break; - - default: - gcc_unreachable (); - } - - cop0 = x; - cop1 = CONST0_RTX (mode); - } - - x = ix86_expand_sse_cmp (operands[0], code, cop0, cop1, - operands[1+negate], operands[2-negate]); - - ix86_expand_sse_movcc (operands[0], x, operands[1+negate], - operands[2-negate]); - return true; -} - /* Expand conditional increment or decrement using adb/sbb instructions. The default case using setcc followed by the conditional move can be done by generic code. */ @@ -11796,7 +10513,7 @@ ix86_expand_int_addcc (rtx operands[]) emit_insn (gen_subdi3_carry_rex64 (operands[0], operands[2], val, compare_op)); break; default: - gcc_unreachable (); + abort (); } } else @@ -11816,7 +10533,7 @@ ix86_expand_int_addcc (rtx operands[]) emit_insn (gen_adddi3_carry_rex64 (operands[0], operands[2], val, compare_op)); break; default: - gcc_unreachable (); + abort (); } } return 1; /* DONE */ @@ -11838,12 +10555,14 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode) else size = (GET_MODE_SIZE (mode) + 4) / 8; - gcc_assert (GET_CODE (operand) != REG || !MMX_REGNO_P (REGNO (operand))); - gcc_assert (size >= 2 && size <= 3); + if (GET_CODE (operand) == REG && MMX_REGNO_P (REGNO (operand))) + abort (); + if (size < 2 || size > 3) + abort (); /* Optimize constant pool reference to immediates. This is used by fp moves, that force all constants to memory to allow combining. */ - if (GET_CODE (operand) == MEM && MEM_READONLY_P (operand)) + if (GET_CODE (operand) == MEM && RTX_UNCHANGING_P (operand)) { rtx tmp = maybe_get_pool_constant (operand); if (tmp) @@ -11853,28 +10572,14 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode) if (GET_CODE (operand) == MEM && !offsettable_memref_p (operand)) { /* The only non-offsetable memories we handle are pushes. */ - int ok = push_operand (operand, VOIDmode); - - gcc_assert (ok); + if (! push_operand (operand, VOIDmode)) + abort (); operand = copy_rtx (operand); PUT_MODE (operand, Pmode); parts[0] = parts[1] = parts[2] = operand; - return size; } - - if (GET_CODE (operand) == CONST_VECTOR) - { - enum machine_mode imode = int_mode_for_mode (mode); - /* Caution: if we looked through a constant pool memory above, - the operand may actually have a different mode now. That's - ok, since we want to pun this all the way back to an integer. */ - operand = simplify_subreg (imode, operand, GET_MODE (operand), 0); - gcc_assert (operand != NULL); - mode = imode; - } - - if (!TARGET_64BIT) + else if (!TARGET_64BIT) { if (mode == DImode) split_di (&operand, 1, &parts[0], &parts[1]); @@ -11882,7 +10587,8 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode) { if (REG_P (operand)) { - gcc_assert (reload_completed); + if (!reload_completed) + abort (); parts[0] = gen_rtx_REG (SImode, REGNO (operand) + 0); parts[1] = gen_rtx_REG (SImode, REGNO (operand) + 1); if (size == 3) @@ -11912,13 +10618,13 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode) REAL_VALUE_TO_TARGET_DOUBLE (r, l); break; default: - gcc_unreachable (); + abort (); } parts[1] = gen_int_mode (l[1], SImode); parts[0] = gen_int_mode (l[0], SImode); } else - gcc_unreachable (); + abort (); } } else @@ -11930,7 +10636,8 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode) enum machine_mode upper_mode = mode==XFmode ? SImode : DImode; if (REG_P (operand)) { - gcc_assert (reload_completed); + if (!reload_completed) + abort (); parts[0] = gen_rtx_REG (DImode, REGNO (operand) + 0); parts[1] = gen_rtx_REG (upper_mode, REGNO (operand) + 1); } @@ -11970,7 +10677,7 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode) parts[1] = immed_double_const (l[2], l[3], DImode); } else - gcc_unreachable (); + abort (); } } @@ -12018,9 +10725,9 @@ ix86_split_long_move (rtx operands[]) /* The only non-offsettable memory we handle is push. */ if (push_operand (operands[0], VOIDmode)) push = 1; - else - gcc_assert (GET_CODE (operands[0]) != MEM - || offsettable_memref_p (operands[0])); + else if (GET_CODE (operands[0]) == MEM + && ! offsettable_memref_p (operands[0])) + abort (); nparts = ix86_split_to_parts (operands[1], part[1], GET_MODE (operands[0])); ix86_split_to_parts (operands[0], part[0], GET_MODE (operands[0])); @@ -12101,20 +10808,12 @@ ix86_split_long_move (rtx operands[]) moving of second half of TFmode value. */ if (GET_MODE (part[1][1]) == SImode) { - switch (GET_CODE (part[1][1])) - { - case MEM: - part[1][1] = adjust_address (part[1][1], DImode, 0); - break; - - case REG: - part[1][1] = gen_rtx_REG (DImode, REGNO (part[1][1])); - break; - - default: - gcc_unreachable (); - } - + if (GET_CODE (part[1][1]) == MEM) + part[1][1] = adjust_address (part[1][1], DImode, 0); + else if (REG_P (part[1][1])) + part[1][1] = gen_rtx_REG (DImode, REGNO (part[1][1])); + else + abort (); if (GET_MODE (part[1][0]) == SImode) part[1][0] = part[1][1]; } @@ -12169,33 +10868,6 @@ ix86_split_long_move (rtx operands[]) operands[6] = part[1][1]; } } - - /* If optimizing for size, attempt to locally unCSE nonzero constants. */ - if (optimize_size) - { - if (GET_CODE (operands[5]) == CONST_INT - && operands[5] != const0_rtx - && REG_P (operands[2])) - { - if (GET_CODE (operands[6]) == CONST_INT - && INTVAL (operands[6]) == INTVAL (operands[5])) - operands[6] = operands[2]; - - if (nparts == 3 - && GET_CODE (operands[7]) == CONST_INT - && INTVAL (operands[7]) == INTVAL (operands[5])) - operands[7] = operands[2]; - } - - if (nparts == 3 - && GET_CODE (operands[6]) == CONST_INT - && operands[6] != const0_rtx - && REG_P (operands[3]) - && GET_CODE (operands[7]) == CONST_INT - && INTVAL (operands[7]) == INTVAL (operands[6])) - operands[7] = operands[3]; - } - emit_move_insn (operands[2], operands[5]); emit_move_insn (operands[3], operands[6]); if (nparts == 3) @@ -12204,209 +10876,90 @@ ix86_split_long_move (rtx operands[]) return; } -/* Helper function of ix86_split_ashl used to generate an SImode/DImode - left shift by a constant, either using a single shift or - a sequence of add instructions. */ - -static void -ix86_expand_ashl_const (rtx operand, int count, enum machine_mode mode) -{ - if (count == 1) - { - emit_insn ((mode == DImode - ? gen_addsi3 - : gen_adddi3) (operand, operand, operand)); - } - else if (!optimize_size - && count * ix86_cost->add <= ix86_cost->shift_const) - { - int i; - for (i=0; i<count; i++) - { - emit_insn ((mode == DImode - ? gen_addsi3 - : gen_adddi3) (operand, operand, operand)); - } - } - else - emit_insn ((mode == DImode - ? gen_ashlsi3 - : gen_ashldi3) (operand, operand, GEN_INT (count))); -} - void -ix86_split_ashl (rtx *operands, rtx scratch, enum machine_mode mode) +ix86_split_ashldi (rtx *operands, rtx scratch) { rtx low[2], high[2]; int count; - const int single_width = mode == DImode ? 32 : 64; if (GET_CODE (operands[2]) == CONST_INT) { - (mode == DImode ? split_di : split_ti) (operands, 2, low, high); - count = INTVAL (operands[2]) & (single_width * 2 - 1); + split_di (operands, 2, low, high); + count = INTVAL (operands[2]) & 63; - if (count >= single_width) + if (count >= 32) { emit_move_insn (high[0], low[1]); emit_move_insn (low[0], const0_rtx); - if (count > single_width) - ix86_expand_ashl_const (high[0], count - single_width, mode); + if (count > 32) + emit_insn (gen_ashlsi3 (high[0], high[0], GEN_INT (count - 32))); } else { if (!rtx_equal_p (operands[0], operands[1])) emit_move_insn (operands[0], operands[1]); - emit_insn ((mode == DImode - ? gen_x86_shld_1 - : gen_x86_64_shld) (high[0], low[0], GEN_INT (count))); - ix86_expand_ashl_const (low[0], count, mode); + emit_insn (gen_x86_shld_1 (high[0], low[0], GEN_INT (count))); + emit_insn (gen_ashlsi3 (low[0], low[0], GEN_INT (count))); } - return; } - - (mode == DImode ? split_di : split_ti) (operands, 1, low, high); - - if (operands[1] == const1_rtx) + else { - /* Assuming we've chosen a QImode capable registers, then 1 << N - can be done with two 32/64-bit shifts, no branches, no cmoves. */ - if (ANY_QI_REG_P (low[0]) && ANY_QI_REG_P (high[0])) - { - rtx s, d, flags = gen_rtx_REG (CCZmode, FLAGS_REG); + if (!rtx_equal_p (operands[0], operands[1])) + emit_move_insn (operands[0], operands[1]); - ix86_expand_clear (low[0]); - ix86_expand_clear (high[0]); - emit_insn (gen_testqi_ccz_1 (operands[2], GEN_INT (single_width))); + split_di (operands, 1, low, high); - d = gen_lowpart (QImode, low[0]); - d = gen_rtx_STRICT_LOW_PART (VOIDmode, d); - s = gen_rtx_EQ (QImode, flags, const0_rtx); - emit_insn (gen_rtx_SET (VOIDmode, d, s)); + emit_insn (gen_x86_shld_1 (high[0], low[0], operands[2])); + emit_insn (gen_ashlsi3 (low[0], low[0], operands[2])); - d = gen_lowpart (QImode, high[0]); - d = gen_rtx_STRICT_LOW_PART (VOIDmode, d); - s = gen_rtx_NE (QImode, flags, const0_rtx); - emit_insn (gen_rtx_SET (VOIDmode, d, s)); - } - - /* Otherwise, we can get the same results by manually performing - a bit extract operation on bit 5/6, and then performing the two - shifts. The two methods of getting 0/1 into low/high are exactly - the same size. Avoiding the shift in the bit extract case helps - pentium4 a bit; no one else seems to care much either way. */ - else + if (TARGET_CMOVE && (! no_new_pseudos || scratch)) { - rtx x; - - if (TARGET_PARTIAL_REG_STALL && !optimize_size) - x = gen_rtx_ZERO_EXTEND (mode == DImode ? SImode : DImode, operands[2]); + if (! no_new_pseudos) + scratch = force_reg (SImode, const0_rtx); else - x = gen_lowpart (mode == DImode ? SImode : DImode, operands[2]); - emit_insn (gen_rtx_SET (VOIDmode, high[0], x)); - - emit_insn ((mode == DImode - ? gen_lshrsi3 - : gen_lshrdi3) (high[0], high[0], GEN_INT (mode == DImode ? 5 : 6))); - emit_insn ((mode == DImode - ? gen_andsi3 - : gen_anddi3) (high[0], high[0], GEN_INT (1))); - emit_move_insn (low[0], high[0]); - emit_insn ((mode == DImode - ? gen_xorsi3 - : gen_xordi3) (low[0], low[0], GEN_INT (1))); - } - - emit_insn ((mode == DImode - ? gen_ashlsi3 - : gen_ashldi3) (low[0], low[0], operands[2])); - emit_insn ((mode == DImode - ? gen_ashlsi3 - : gen_ashldi3) (high[0], high[0], operands[2])); - return; - } + emit_move_insn (scratch, const0_rtx); - if (operands[1] == constm1_rtx) - { - /* For -1 << N, we can avoid the shld instruction, because we - know that we're shifting 0...31/63 ones into a -1. */ - emit_move_insn (low[0], constm1_rtx); - if (optimize_size) - emit_move_insn (high[0], low[0]); + emit_insn (gen_x86_shift_adj_1 (high[0], low[0], operands[2], + scratch)); + } else - emit_move_insn (high[0], constm1_rtx); - } - else - { - if (!rtx_equal_p (operands[0], operands[1])) - emit_move_insn (operands[0], operands[1]); - - (mode == DImode ? split_di : split_ti) (operands, 1, low, high); - emit_insn ((mode == DImode - ? gen_x86_shld_1 - : gen_x86_64_shld) (high[0], low[0], operands[2])); + emit_insn (gen_x86_shift_adj_2 (high[0], low[0], operands[2])); } - - emit_insn ((mode == DImode ? gen_ashlsi3 : gen_ashldi3) (low[0], low[0], operands[2])); - - if (TARGET_CMOVE && scratch) - { - ix86_expand_clear (scratch); - emit_insn ((mode == DImode - ? gen_x86_shift_adj_1 - : gen_x86_64_shift_adj) (high[0], low[0], operands[2], scratch)); - } - else - emit_insn (gen_x86_shift_adj_2 (high[0], low[0], operands[2])); } void -ix86_split_ashr (rtx *operands, rtx scratch, enum machine_mode mode) +ix86_split_ashrdi (rtx *operands, rtx scratch) { rtx low[2], high[2]; int count; - const int single_width = mode == DImode ? 32 : 64; if (GET_CODE (operands[2]) == CONST_INT) { - (mode == DImode ? split_di : split_ti) (operands, 2, low, high); - count = INTVAL (operands[2]) & (single_width * 2 - 1); - - if (count == single_width * 2 - 1) - { - emit_move_insn (high[0], high[1]); - emit_insn ((mode == DImode - ? gen_ashrsi3 - : gen_ashrdi3) (high[0], high[0], - GEN_INT (single_width - 1))); - emit_move_insn (low[0], high[0]); + split_di (operands, 2, low, high); + count = INTVAL (operands[2]) & 63; - } - else if (count >= single_width) + if (count >= 32) { emit_move_insn (low[0], high[1]); - emit_move_insn (high[0], low[0]); - emit_insn ((mode == DImode - ? gen_ashrsi3 - : gen_ashrdi3) (high[0], high[0], - GEN_INT (single_width - 1))); - if (count > single_width) - emit_insn ((mode == DImode - ? gen_ashrsi3 - : gen_ashrdi3) (low[0], low[0], - GEN_INT (count - single_width))); + + if (! reload_completed) + emit_insn (gen_ashrsi3 (high[0], low[0], GEN_INT (31))); + else + { + emit_move_insn (high[0], low[0]); + emit_insn (gen_ashrsi3 (high[0], high[0], GEN_INT (31))); + } + + if (count > 32) + emit_insn (gen_ashrsi3 (low[0], low[0], GEN_INT (count - 32))); } else { if (!rtx_equal_p (operands[0], operands[1])) emit_move_insn (operands[0], operands[1]); - emit_insn ((mode == DImode - ? gen_x86_shrd_1 - : gen_x86_64_shrd) (low[0], high[0], GEN_INT (count))); - emit_insn ((mode == DImode - ? gen_ashrsi3 - : gen_ashrdi3) (high[0], high[0], GEN_INT (count))); + emit_insn (gen_x86_shrd_1 (low[0], high[0], GEN_INT (count))); + emit_insn (gen_ashrsi3 (high[0], high[0], GEN_INT (count))); } } else @@ -12414,26 +10967,19 @@ ix86_split_ashr (rtx *operands, rtx scratch, enum machine_mode mode) if (!rtx_equal_p (operands[0], operands[1])) emit_move_insn (operands[0], operands[1]); - (mode == DImode ? split_di : split_ti) (operands, 1, low, high); + split_di (operands, 1, low, high); - emit_insn ((mode == DImode - ? gen_x86_shrd_1 - : gen_x86_64_shrd) (low[0], high[0], operands[2])); - emit_insn ((mode == DImode - ? gen_ashrsi3 - : gen_ashrdi3) (high[0], high[0], operands[2])); + emit_insn (gen_x86_shrd_1 (low[0], high[0], operands[2])); + emit_insn (gen_ashrsi3 (high[0], high[0], operands[2])); - if (TARGET_CMOVE && scratch) + if (TARGET_CMOVE && (! no_new_pseudos || scratch)) { + if (! no_new_pseudos) + scratch = gen_reg_rtx (SImode); emit_move_insn (scratch, high[0]); - emit_insn ((mode == DImode - ? gen_ashrsi3 - : gen_ashrdi3) (scratch, scratch, - GEN_INT (single_width - 1))); - emit_insn ((mode == DImode - ? gen_x86_shift_adj_1 - : gen_x86_64_shift_adj) (low[0], high[0], operands[2], - scratch)); + emit_insn (gen_ashrsi3 (scratch, scratch, GEN_INT (31))); + emit_insn (gen_x86_shift_adj_1 (low[0], high[0], operands[2], + scratch)); } else emit_insn (gen_x86_shift_adj_3 (low[0], high[0], operands[2])); @@ -12441,38 +10987,30 @@ ix86_split_ashr (rtx *operands, rtx scratch, enum machine_mode mode) } void -ix86_split_lshr (rtx *operands, rtx scratch, enum machine_mode mode) +ix86_split_lshrdi (rtx *operands, rtx scratch) { rtx low[2], high[2]; int count; - const int single_width = mode == DImode ? 32 : 64; if (GET_CODE (operands[2]) == CONST_INT) { - (mode == DImode ? split_di : split_ti) (operands, 2, low, high); - count = INTVAL (operands[2]) & (single_width * 2 - 1); + split_di (operands, 2, low, high); + count = INTVAL (operands[2]) & 63; - if (count >= single_width) + if (count >= 32) { emit_move_insn (low[0], high[1]); - ix86_expand_clear (high[0]); + emit_move_insn (high[0], const0_rtx); - if (count > single_width) - emit_insn ((mode == DImode - ? gen_lshrsi3 - : gen_lshrdi3) (low[0], low[0], - GEN_INT (count - single_width))); + if (count > 32) + emit_insn (gen_lshrsi3 (low[0], low[0], GEN_INT (count - 32))); } else { if (!rtx_equal_p (operands[0], operands[1])) emit_move_insn (operands[0], operands[1]); - emit_insn ((mode == DImode - ? gen_x86_shrd_1 - : gen_x86_64_shrd) (low[0], high[0], GEN_INT (count))); - emit_insn ((mode == DImode - ? gen_lshrsi3 - : gen_lshrdi3) (high[0], high[0], GEN_INT (count))); + emit_insn (gen_x86_shrd_1 (low[0], high[0], GEN_INT (count))); + emit_insn (gen_lshrsi3 (high[0], high[0], GEN_INT (count))); } } else @@ -12480,23 +11018,21 @@ ix86_split_lshr (rtx *operands, rtx scratch, enum machine_mode mode) if (!rtx_equal_p (operands[0], operands[1])) emit_move_insn (operands[0], operands[1]); - (mode == DImode ? split_di : split_ti) (operands, 1, low, high); + split_di (operands, 1, low, high); - emit_insn ((mode == DImode - ? gen_x86_shrd_1 - : gen_x86_64_shrd) (low[0], high[0], operands[2])); - emit_insn ((mode == DImode - ? gen_lshrsi3 - : gen_lshrdi3) (high[0], high[0], operands[2])); + emit_insn (gen_x86_shrd_1 (low[0], high[0], operands[2])); + emit_insn (gen_lshrsi3 (high[0], high[0], operands[2])); /* Heh. By reversing the arguments, we can reuse this pattern. */ - if (TARGET_CMOVE && scratch) + if (TARGET_CMOVE && (! no_new_pseudos || scratch)) { - ix86_expand_clear (scratch); - emit_insn ((mode == DImode - ? gen_x86_shift_adj_1 - : gen_x86_64_shift_adj) (low[0], high[0], operands[2], - scratch)); + if (! no_new_pseudos) + scratch = force_reg (SImode, const0_rtx); + else + emit_move_insn (scratch, const0_rtx); + + emit_insn (gen_x86_shift_adj_1 (low[0], high[0], operands[2], + scratch)); } else emit_insn (gen_x86_shift_adj_2 (low[0], high[0], operands[2])); @@ -12544,9 +11080,9 @@ ix86_zero_extend_to_Pmode (rtx exp) } /* Expand string move (memcpy) operation. Use i386 string operations when - profitable. expand_clrmem contains similar code. */ + profitable. expand_clrstr contains similar code. */ int -ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp) +ix86_expand_movstr (rtx dst, rtx src, rtx count_exp, rtx align_exp) { rtx srcreg, destreg, countreg, srcexp, destexp; enum machine_mode counter_mode; @@ -12574,14 +11110,14 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp) /* Figure out proper mode for counter. For 32bits it is always SImode, for 64bits use SImode when possible, otherwise DImode. Set count to number of bytes copied when known at compile time. */ - if (!TARGET_64BIT - || GET_MODE (count_exp) == SImode - || x86_64_zext_immediate_operand (count_exp, VOIDmode)) + if (!TARGET_64BIT || GET_MODE (count_exp) == SImode + || x86_64_zero_extended_value (count_exp)) counter_mode = SImode; else counter_mode = DImode; - gcc_assert (counter_mode == SImode || counter_mode == DImode); + if (counter_mode != SImode && counter_mode != DImode) + abort (); destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0)); if (destreg != XEXP (dst, 0)) @@ -12591,20 +11127,9 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp) src = replace_equiv_address_nv (src, srcreg); /* When optimizing for size emit simple rep ; movsb instruction for - counts not divisible by 4, except when (movsl;)*(movsw;)?(movsb;)? - sequence is shorter than mov{b,l} $count, %{ecx,cl}; rep; movsb. - Sice of (movsl;)*(movsw;)?(movsb;)? sequence is - count / 4 + (count & 3), the other sequence is either 4 or 7 bytes, - but we don't know whether upper 24 (resp. 56) bits of %ecx will be - known to be zero or not. The rep; movsb sequence causes higher - register pressure though, so take that into account. */ - - if ((!optimize || optimize_size) - && (count == 0 - || ((count & 0x03) - && (!optimize_size - || count > 5 * 4 - || (count & 3) + count / 4 > 6)))) + counts not divisible by 4. */ + + if ((!optimize || optimize_size) && (count == 0 || (count & 0x03))) { emit_insn (gen_cld ()); countreg = ix86_zero_extend_to_Pmode (count_exp); @@ -12630,36 +11155,19 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp) emit_insn (gen_cld ()); if (count & ~(size - 1)) { - if ((TARGET_SINGLE_STRINGOP || optimize_size) && count < 5 * 4) - { - enum machine_mode movs_mode = size == 4 ? SImode : DImode; + countreg = copy_to_mode_reg (counter_mode, + GEN_INT ((count >> (size == 4 ? 2 : 3)) + & (TARGET_64BIT ? -1 : 0x3fffffff))); + countreg = ix86_zero_extend_to_Pmode (countreg); + + destexp = gen_rtx_ASHIFT (Pmode, countreg, + GEN_INT (size == 4 ? 2 : 3)); + srcexp = gen_rtx_PLUS (Pmode, destexp, srcreg); + destexp = gen_rtx_PLUS (Pmode, destexp, destreg); - while (offset < (count & ~(size - 1))) - { - srcmem = adjust_automodify_address_nv (src, movs_mode, - srcreg, offset); - dstmem = adjust_automodify_address_nv (dst, movs_mode, - destreg, offset); - emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem)); - offset += size; - } - } - else - { - countreg = GEN_INT ((count >> (size == 4 ? 2 : 3)) - & (TARGET_64BIT ? -1 : 0x3fffffff)); - countreg = copy_to_mode_reg (counter_mode, countreg); - countreg = ix86_zero_extend_to_Pmode (countreg); - - destexp = gen_rtx_ASHIFT (Pmode, countreg, - GEN_INT (size == 4 ? 2 : 3)); - srcexp = gen_rtx_PLUS (Pmode, destexp, srcreg); - destexp = gen_rtx_PLUS (Pmode, destexp, destreg); - - emit_insn (gen_rep_mov (destreg, dst, srcreg, src, - countreg, destexp, srcexp)); - offset = count & ~(size - 1); - } + emit_insn (gen_rep_mov (destreg, dst, srcreg, src, + countreg, destexp, srcexp)); + offset = count & ~(size - 1); } if (size == 8 && (count & 0x04)) { @@ -12851,9 +11359,9 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp) } /* Expand string clear operation (bzero). Use i386 string operations when - profitable. expand_movmem contains similar code. */ + profitable. expand_movstr contains similar code. */ int -ix86_expand_clrmem (rtx dst, rtx count_exp, rtx align_exp) +ix86_expand_clrstr (rtx dst, rtx count_exp, rtx align_exp) { rtx destreg, zeroreg, countreg, destexp; enum machine_mode counter_mode; @@ -12880,9 +11388,8 @@ ix86_expand_clrmem (rtx dst, rtx count_exp, rtx align_exp) /* Figure out proper mode for counter. For 32bits it is always SImode, for 64bits use SImode when possible, otherwise DImode. Set count to number of bytes copied when known at compile time. */ - if (!TARGET_64BIT - || GET_MODE (count_exp) == SImode - || x86_64_zext_immediate_operand (count_exp, VOIDmode)) + if (!TARGET_64BIT || GET_MODE (count_exp) == SImode + || x86_64_zero_extended_value (count_exp)) counter_mode = SImode; else counter_mode = DImode; @@ -12891,20 +11398,13 @@ ix86_expand_clrmem (rtx dst, rtx count_exp, rtx align_exp) if (destreg != XEXP (dst, 0)) dst = replace_equiv_address_nv (dst, destreg); + emit_insn (gen_cld ()); /* When optimizing for size emit simple rep ; movsb instruction for - counts not divisible by 4. The movl $N, %ecx; rep; stosb - sequence is 7 bytes long, so if optimizing for size and count is - small enough that some stosl, stosw and stosb instructions without - rep are shorter, fall back into the next if. */ + counts not divisible by 4. */ - if ((!optimize || optimize_size) - && (count == 0 - || ((count & 0x03) - && (!optimize_size || (count & 0x03) + (count >> 2) > 7)))) + if ((!optimize || optimize_size) && (count == 0 || (count & 0x03))) { - emit_insn (gen_cld ()); - countreg = ix86_zero_extend_to_Pmode (count_exp); zeroreg = copy_to_mode_reg (QImode, const0_rtx); destexp = gen_rtx_PLUS (Pmode, destreg, countreg); @@ -12918,54 +11418,17 @@ ix86_expand_clrmem (rtx dst, rtx count_exp, rtx align_exp) int size = TARGET_64BIT && !optimize_size ? 8 : 4; unsigned HOST_WIDE_INT offset = 0; - emit_insn (gen_cld ()); - zeroreg = copy_to_mode_reg (size == 4 ? SImode : DImode, const0_rtx); if (count & ~(size - 1)) { - unsigned HOST_WIDE_INT repcount; - unsigned int max_nonrep; - - repcount = count >> (size == 4 ? 2 : 3); - if (!TARGET_64BIT) - repcount &= 0x3fffffff; - - /* movl $N, %ecx; rep; stosl is 7 bytes, while N x stosl is N bytes. - movl $N, %ecx; rep; stosq is 8 bytes, while N x stosq is 2xN - bytes. In both cases the latter seems to be faster for small - values of N. */ - max_nonrep = size == 4 ? 7 : 4; - if (!optimize_size) - switch (ix86_tune) - { - case PROCESSOR_PENTIUM4: - case PROCESSOR_NOCONA: - max_nonrep = 3; - break; - default: - break; - } - - if (repcount <= max_nonrep) - while (repcount-- > 0) - { - rtx mem = adjust_automodify_address_nv (dst, - GET_MODE (zeroreg), - destreg, offset); - emit_insn (gen_strset (destreg, mem, zeroreg)); - offset += size; - } - else - { - countreg = copy_to_mode_reg (counter_mode, GEN_INT (repcount)); - countreg = ix86_zero_extend_to_Pmode (countreg); - destexp = gen_rtx_ASHIFT (Pmode, countreg, - GEN_INT (size == 4 ? 2 : 3)); - destexp = gen_rtx_PLUS (Pmode, destexp, destreg); - emit_insn (gen_rep_stos (destreg, countreg, dst, zeroreg, - destexp)); - offset = count & ~(size - 1); - } + countreg = copy_to_mode_reg (counter_mode, + GEN_INT ((count >> (size == 4 ? 2 : 3)) + & (TARGET_64BIT ? -1 : 0x3fffffff))); + countreg = ix86_zero_extend_to_Pmode (countreg); + destexp = gen_rtx_ASHIFT (Pmode, countreg, GEN_INT (size == 4 ? 2 : 3)); + destexp = gen_rtx_PLUS (Pmode, destexp, destreg); + emit_insn (gen_rep_stos (destreg, countreg, dst, zeroreg, destexp)); + offset = count & ~(size - 1); } if (size == 8 && (count & 0x04)) { @@ -13241,9 +11704,9 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx) emit_cmp_and_jump_insns (align_rtx, const0_rtx, EQ, NULL, Pmode, 1, align_4_label); - emit_cmp_and_jump_insns (align_rtx, const2_rtx, EQ, NULL, + emit_cmp_and_jump_insns (align_rtx, GEN_INT (2), EQ, NULL, Pmode, 1, align_2_label); - emit_cmp_and_jump_insns (align_rtx, const2_rtx, GTU, NULL, + emit_cmp_and_jump_insns (align_rtx, GEN_INT (2), GTU, NULL, Pmode, 1, align_3_label); } else @@ -13251,7 +11714,7 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx) /* Since the alignment is 2, we have to check 2 or 0 bytes; check if is aligned to 4 - byte. */ - align_rtx = expand_binop (Pmode, and_optab, scratch1, const2_rtx, + align_rtx = expand_binop (Pmode, and_optab, scratch1, GEN_INT (2), NULL_RTX, 0, OPTAB_WIDEN); emit_cmp_and_jump_insns (align_rtx, const0_rtx, EQ, NULL, @@ -13337,7 +11800,7 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx) tmpreg))); /* Emit lea manually to avoid clobbering of flags. */ emit_insn (gen_rtx_SET (SImode, reg2, - gen_rtx_PLUS (Pmode, out, const2_rtx))); + gen_rtx_PLUS (Pmode, out, GEN_INT (2)))); tmp = gen_rtx_REG (CCNOmode, FLAGS_REG); tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); @@ -13364,9 +11827,9 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx) /* Not in the first two. Move two bytes forward. */ emit_insn (gen_lshrsi3 (tmpreg, tmpreg, GEN_INT (16))); if (TARGET_64BIT) - emit_insn (gen_adddi3 (out, out, const2_rtx)); + emit_insn (gen_adddi3 (out, out, GEN_INT (2))); else - emit_insn (gen_addsi3 (out, out, const2_rtx)); + emit_insn (gen_addsi3 (out, out, GEN_INT (2))); emit_label (end_2_label); @@ -13393,23 +11856,18 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, if (pop == const0_rtx) pop = NULL; - gcc_assert (!TARGET_64BIT || !pop); + if (TARGET_64BIT && pop) + abort (); - if (TARGET_MACHO && !TARGET_64BIT) - { #if TARGET_MACHO - if (flag_pic && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF) - fnaddr = machopic_indirect_call_target (fnaddr); -#endif - } - else - { - /* Static functions and indirect calls don't need the pic register. */ - if (! TARGET_64BIT && flag_pic - && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF - && ! SYMBOL_REF_LOCAL_P (XEXP (fnaddr, 0))) - use_reg (&use, pic_offset_table_rtx); - } + if (flag_pic && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF) + fnaddr = machopic_indirect_call_target (fnaddr); +#else + /* Static functions and indirect calls don't need the pic register. */ + if (! TARGET_64BIT && flag_pic + && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF + && ! SYMBOL_REF_LOCAL_P (XEXP (fnaddr, 0))) + use_reg (&use, pic_offset_table_rtx); if (TARGET_64BIT && INTVAL (callarg2) >= 0) { @@ -13417,6 +11875,7 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, emit_move_insn (al, callarg2); use_reg (&use, al); } +#endif /* TARGET_MACHO */ if (! call_insn_operand (XEXP (fnaddr, 0), Pmode)) { @@ -13460,7 +11919,6 @@ ix86_init_machine_status (void) f = ggc_alloc_cleared (sizeof (struct machine_function)); f->use_fast_prologue_epilogue_nregs = -1; - f->tls_descriptor_call_expanded_p = 0; return f; } @@ -13472,11 +11930,12 @@ ix86_init_machine_status (void) which slot to use. */ rtx -assign_386_stack_local (enum machine_mode mode, enum ix86_stack_slot n) +assign_386_stack_local (enum machine_mode mode, int n) { struct stack_local_entry *s; - gcc_assert (n < MAX_386_STACK_LOCALS); + if (n < 0 || n >= MAX_386_STACK_LOCALS) + abort (); for (s = ix86_stack_locals; s; s = s->next) if (s->mode == mode && s->n == n) @@ -13503,43 +11962,23 @@ ix86_tls_get_addr (void) if (!ix86_tls_symbol) { ix86_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, - (TARGET_ANY_GNU_TLS - && !TARGET_64BIT) + (TARGET_GNU_TLS && !TARGET_64BIT) ? "___tls_get_addr" : "__tls_get_addr"); } return ix86_tls_symbol; } - -/* Construct the SYMBOL_REF for the _TLS_MODULE_BASE_ symbol. */ - -static GTY(()) rtx ix86_tls_module_base_symbol; -rtx -ix86_tls_module_base (void) -{ - - if (!ix86_tls_module_base_symbol) - { - ix86_tls_module_base_symbol = gen_rtx_SYMBOL_REF (Pmode, - "_TLS_MODULE_BASE_"); - SYMBOL_REF_FLAGS (ix86_tls_module_base_symbol) - |= TLS_MODEL_GLOBAL_DYNAMIC << SYMBOL_FLAG_TLS_SHIFT; - } - - return ix86_tls_module_base_symbol; -} /* Calculate the length of the memory address in the instruction encoding. Does not include the one-byte modrm, opcode, or prefix. */ -int +static int memory_address_length (rtx addr) { struct ix86_address parts; rtx base, index, disp; int len; - int ok; if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_INC @@ -13547,13 +11986,8 @@ memory_address_length (rtx addr) || GET_CODE (addr) == POST_MODIFY) return 0; - ok = ix86_decompose_address (addr, &parts); - gcc_assert (ok); - - if (parts.base && GET_CODE (parts.base) == SUBREG) - parts.base = SUBREG_REG (parts.base); - if (parts.index && GET_CODE (parts.index) == SUBREG) - parts.index = SUBREG_REG (parts.index); + if (! ix86_decompose_address (addr, &parts)) + abort (); base = parts.base; index = parts.index; @@ -13585,7 +12019,9 @@ memory_address_length (rtx addr) /* Find the length of the displacement constant. */ if (disp) { - if (base && satisfies_constraint_K (disp)) + if (GET_CODE (disp) == CONST_INT + && CONST_OK_FOR_LETTER_P (INTVAL (disp), 'K') + && base) len = 1; else len = 4; @@ -13617,8 +12053,11 @@ ix86_attr_length_immediate_default (rtx insn, int shortform) for (i = recog_data.n_operands - 1; i >= 0; --i) if (CONSTANT_P (recog_data.operand[i])) { - gcc_assert (!len); - if (shortform && satisfies_constraint_K (recog_data.operand[i])) + if (len) + abort (); + if (shortform + && GET_CODE (recog_data.operand[i]) == CONST_INT + && CONST_OK_FOR_LETTER_P (INTVAL (recog_data.operand[i]), 'K')) len = 1; else { @@ -13653,11 +12092,18 @@ ix86_attr_length_address_default (rtx insn) if (get_attr_type (insn) == TYPE_LEA) { rtx set = PATTERN (insn); - - if (GET_CODE (set) == PARALLEL) + if (GET_CODE (set) == SET) + ; + else if (GET_CODE (set) == PARALLEL + && GET_CODE (XVECEXP (set, 0, 0)) == SET) set = XVECEXP (set, 0, 0); - - gcc_assert (GET_CODE (set) == SET); + else + { +#ifdef ENABLE_CHECKING + abort (); +#endif + return 0; + } return memory_address_length (SET_SRC (set)); } @@ -13687,9 +12133,6 @@ ix86_issue_rate (void) case PROCESSOR_PENTIUM4: case PROCESSOR_ATHLON: case PROCESSOR_K8: - case PROCESSOR_NOCONA: - case PROCESSOR_GENERIC32: - case PROCESSOR_GENERIC64: return 3; default: @@ -13701,7 +12144,7 @@ ix86_issue_rate (void) by DEP_INSN and nothing set by DEP_INSN. */ static int -ix86_flags_dependent (rtx insn, rtx dep_insn, enum attr_type insn_type) +ix86_flags_dependant (rtx insn, rtx dep_insn, enum attr_type insn_type) { rtx set, set2; @@ -13746,7 +12189,7 @@ ix86_flags_dependent (rtx insn, rtx dep_insn, enum attr_type insn_type) address with operands set by DEP_INSN. */ static int -ix86_agi_dependent (rtx insn, rtx dep_insn, enum attr_type insn_type) +ix86_agi_dependant (rtx insn, rtx dep_insn, enum attr_type insn_type) { rtx addr; @@ -13754,12 +12197,13 @@ ix86_agi_dependent (rtx insn, rtx dep_insn, enum attr_type insn_type) && TARGET_PENTIUM) { addr = PATTERN (insn); - - if (GET_CODE (addr) == PARALLEL) + if (GET_CODE (addr) == SET) + ; + else if (GET_CODE (addr) == PARALLEL + && GET_CODE (XVECEXP (addr, 0, 0)) == SET) addr = XVECEXP (addr, 0, 0); - - gcc_assert (GET_CODE (addr) == SET); - + else + abort (); addr = SET_SRC (addr); } else @@ -13783,7 +12227,7 @@ static int ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) { enum attr_type insn_type, dep_insn_type; - enum attr_memory memory; + enum attr_memory memory, dep_memory; rtx set, set2; int dep_insn_code_number; @@ -13804,22 +12248,30 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) { case PROCESSOR_PENTIUM: /* Address Generation Interlock adds a cycle of latency. */ - if (ix86_agi_dependent (insn, dep_insn, insn_type)) + if (ix86_agi_dependant (insn, dep_insn, insn_type)) cost += 1; /* ??? Compares pair with jump/setcc. */ - if (ix86_flags_dependent (insn, dep_insn, insn_type)) + if (ix86_flags_dependant (insn, dep_insn, insn_type)) cost = 0; /* Floating point stores require value to be ready one cycle earlier. */ if (insn_type == TYPE_FMOV && get_attr_memory (insn) == MEMORY_STORE - && !ix86_agi_dependent (insn, dep_insn, insn_type)) + && !ix86_agi_dependant (insn, dep_insn, insn_type)) cost += 1; break; case PROCESSOR_PENTIUMPRO: memory = get_attr_memory (insn); + dep_memory = get_attr_memory (dep_insn); + + /* Since we can't represent delayed latencies of load+operation, + increase the cost here for non-imov insns. */ + if (dep_insn_type != TYPE_IMOV + && dep_insn_type != TYPE_FMOV + && (dep_memory == MEMORY_LOAD || dep_memory == MEMORY_BOTH)) + cost += 1; /* INT->FP conversion is expensive. */ if (get_attr_fp_int_src (dep_insn)) @@ -13837,7 +12289,7 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) in parallel with previous instruction in case previous instruction is not needed to compute the address. */ if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH) - && !ix86_agi_dependent (insn, dep_insn, insn_type)) + && !ix86_agi_dependant (insn, dep_insn, insn_type)) { /* Claim moves to take one cycle, as core can issue one load at time and the next load can start cycle later. */ @@ -13851,13 +12303,18 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) case PROCESSOR_K6: memory = get_attr_memory (insn); - + dep_memory = get_attr_memory (dep_insn); /* The esp dependency is resolved before the instruction is really finished. */ if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP) && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP)) return 1; + /* Since we can't represent delayed latencies of load+operation, + increase the cost here for non-imov insns. */ + if (dep_memory == MEMORY_LOAD || dep_memory == MEMORY_BOTH) + cost += (dep_insn_type != TYPE_IMOV) ? 2 : 1; + /* INT->FP conversion is expensive. */ if (get_attr_fp_int_src (dep_insn)) cost += 5; @@ -13866,7 +12323,7 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) in parallel with previous instruction in case previous instruction is not needed to compute the address. */ if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH) - && !ix86_agi_dependent (insn, dep_insn, insn_type)) + && !ix86_agi_dependant (insn, dep_insn, insn_type)) { /* Claim moves to take one cycle, as core can issue one load at time and the next load can start cycle later. */ @@ -13882,15 +12339,14 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) case PROCESSOR_ATHLON: case PROCESSOR_K8: - case PROCESSOR_GENERIC32: - case PROCESSOR_GENERIC64: memory = get_attr_memory (insn); + dep_memory = get_attr_memory (dep_insn); /* Show ability of reorder buffer to hide latency of load by executing in parallel with previous instruction in case previous instruction is not needed to compute the address. */ if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH) - && !ix86_agi_dependent (insn, dep_insn, insn_type)) + && !ix86_agi_dependant (insn, dep_insn, insn_type)) { enum attr_unit unit = get_attr_unit (insn); int loadcost = 3; @@ -13918,6 +12374,248 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) return cost; } +static union +{ + struct ppro_sched_data + { + rtx decode[3]; + int issued_this_cycle; + } ppro; +} ix86_sched_data; + +static enum attr_ppro_uops +ix86_safe_ppro_uops (rtx insn) +{ + if (recog_memoized (insn) >= 0) + return get_attr_ppro_uops (insn); + else + return PPRO_UOPS_MANY; +} + +static void +ix86_dump_ppro_packet (FILE *dump) +{ + if (ix86_sched_data.ppro.decode[0]) + { + fprintf (dump, "PPRO packet: %d", + INSN_UID (ix86_sched_data.ppro.decode[0])); + if (ix86_sched_data.ppro.decode[1]) + fprintf (dump, " %d", INSN_UID (ix86_sched_data.ppro.decode[1])); + if (ix86_sched_data.ppro.decode[2]) + fprintf (dump, " %d", INSN_UID (ix86_sched_data.ppro.decode[2])); + fputc ('\n', dump); + } +} + +/* We're beginning a new block. Initialize data structures as necessary. */ + +static void +ix86_sched_init (FILE *dump ATTRIBUTE_UNUSED, + int sched_verbose ATTRIBUTE_UNUSED, + int veclen ATTRIBUTE_UNUSED) +{ + memset (&ix86_sched_data, 0, sizeof (ix86_sched_data)); +} + +/* Shift INSN to SLOT, and shift everything else down. */ + +static void +ix86_reorder_insn (rtx *insnp, rtx *slot) +{ + if (insnp != slot) + { + rtx insn = *insnp; + do + insnp[0] = insnp[1]; + while (++insnp != slot); + *insnp = insn; + } +} + +static void +ix86_sched_reorder_ppro (rtx *ready, rtx *e_ready) +{ + rtx decode[3]; + enum attr_ppro_uops cur_uops; + int issued_this_cycle; + rtx *insnp; + int i; + + /* At this point .ppro.decode contains the state of the three + decoders from last "cycle". That is, those insns that were + actually independent. But here we're scheduling for the + decoder, and we may find things that are decodable in the + same cycle. */ + + memcpy (decode, ix86_sched_data.ppro.decode, sizeof (decode)); + issued_this_cycle = 0; + + insnp = e_ready; + cur_uops = ix86_safe_ppro_uops (*insnp); + + /* If the decoders are empty, and we've a complex insn at the + head of the priority queue, let it issue without complaint. */ + if (decode[0] == NULL) + { + if (cur_uops == PPRO_UOPS_MANY) + { + decode[0] = *insnp; + goto ppro_done; + } + + /* Otherwise, search for a 2-4 uop unsn to issue. */ + while (cur_uops != PPRO_UOPS_FEW) + { + if (insnp == ready) + break; + cur_uops = ix86_safe_ppro_uops (*--insnp); + } + + /* If so, move it to the head of the line. */ + if (cur_uops == PPRO_UOPS_FEW) + ix86_reorder_insn (insnp, e_ready); + + /* Issue the head of the queue. */ + issued_this_cycle = 1; + decode[0] = *e_ready--; + } + + /* Look for simple insns to fill in the other two slots. */ + for (i = 1; i < 3; ++i) + if (decode[i] == NULL) + { + if (ready > e_ready) + goto ppro_done; + + insnp = e_ready; + cur_uops = ix86_safe_ppro_uops (*insnp); + while (cur_uops != PPRO_UOPS_ONE) + { + if (insnp == ready) + break; + cur_uops = ix86_safe_ppro_uops (*--insnp); + } + + /* Found one. Move it to the head of the queue and issue it. */ + if (cur_uops == PPRO_UOPS_ONE) + { + ix86_reorder_insn (insnp, e_ready); + decode[i] = *e_ready--; + issued_this_cycle++; + continue; + } + + /* ??? Didn't find one. Ideally, here we would do a lazy split + of 2-uop insns, issue one and queue the other. */ + } + + ppro_done: + if (issued_this_cycle == 0) + issued_this_cycle = 1; + ix86_sched_data.ppro.issued_this_cycle = issued_this_cycle; +} + +/* We are about to being issuing insns for this clock cycle. + Override the default sort algorithm to better slot instructions. */ +static int +ix86_sched_reorder (FILE *dump ATTRIBUTE_UNUSED, + int sched_verbose ATTRIBUTE_UNUSED, rtx *ready, + int *n_readyp, int clock_var ATTRIBUTE_UNUSED) +{ + int n_ready = *n_readyp; + rtx *e_ready = ready + n_ready - 1; + + /* Make sure to go ahead and initialize key items in + ix86_sched_data if we are not going to bother trying to + reorder the ready queue. */ + if (n_ready < 2) + { + ix86_sched_data.ppro.issued_this_cycle = 1; + goto out; + } + + switch (ix86_tune) + { + default: + break; + + case PROCESSOR_PENTIUMPRO: + ix86_sched_reorder_ppro (ready, e_ready); + break; + } + +out: + return ix86_issue_rate (); +} + +/* We are about to issue INSN. Return the number of insns left on the + ready queue that can be issued this cycle. */ + +static int +ix86_variable_issue (FILE *dump, int sched_verbose, rtx insn, + int can_issue_more) +{ + int i; + switch (ix86_tune) + { + default: + return can_issue_more - 1; + + case PROCESSOR_PENTIUMPRO: + { + enum attr_ppro_uops uops = ix86_safe_ppro_uops (insn); + + if (uops == PPRO_UOPS_MANY) + { + if (sched_verbose) + ix86_dump_ppro_packet (dump); + ix86_sched_data.ppro.decode[0] = insn; + ix86_sched_data.ppro.decode[1] = NULL; + ix86_sched_data.ppro.decode[2] = NULL; + if (sched_verbose) + ix86_dump_ppro_packet (dump); + ix86_sched_data.ppro.decode[0] = NULL; + } + else if (uops == PPRO_UOPS_FEW) + { + if (sched_verbose) + ix86_dump_ppro_packet (dump); + ix86_sched_data.ppro.decode[0] = insn; + ix86_sched_data.ppro.decode[1] = NULL; + ix86_sched_data.ppro.decode[2] = NULL; + } + else + { + for (i = 0; i < 3; ++i) + if (ix86_sched_data.ppro.decode[i] == NULL) + { + ix86_sched_data.ppro.decode[i] = insn; + break; + } + if (i == 3) + abort (); + if (i == 2) + { + if (sched_verbose) + ix86_dump_ppro_packet (dump); + ix86_sched_data.ppro.decode[0] = NULL; + ix86_sched_data.ppro.decode[1] = NULL; + ix86_sched_data.ppro.decode[2] = NULL; + } + } + } + return --ix86_sched_data.ppro.issued_this_cycle; + } +} + +static int +ia32_use_dfa_pipeline_interface (void) +{ + if (TARGET_PENTIUM || TARGET_ATHLON_K8) + return 1; + return 0; +} + /* How many alternative schedules to try. This should be as wide as the scheduling freedom in the DFA, but no wider. Making this value too large results extra work for the scheduler. */ @@ -13927,13 +12625,8 @@ ia32_multipass_dfa_lookahead (void) { if (ix86_tune == PROCESSOR_PENTIUM) return 2; - - if (ix86_tune == PROCESSOR_PENTIUMPRO - || ix86_tune == PROCESSOR_K6) - return 1; - else - return 0; + return 0; } @@ -13954,6 +12647,7 @@ ix86_constant_alignment (tree exp, int align) return 128; } else if (!optimize_size && TREE_CODE (exp) == STRING_CST + && !TARGET_NO_ALIGN_LONG_STRINGS && TREE_STRING_LENGTH (exp) >= 31 && align < BITS_PER_WORD) return BITS_PER_WORD; @@ -13968,15 +12662,12 @@ ix86_constant_alignment (tree exp, int align) int ix86_data_alignment (tree type, int align) { - int max_align = optimize_size ? BITS_PER_WORD : 256; - if (AGGREGATE_TYPE_P (type) - && TYPE_SIZE (type) - && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST - && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= (unsigned) max_align - || TREE_INT_CST_HIGH (TYPE_SIZE (type))) - && align < max_align) - align = max_align; + && TYPE_SIZE (type) + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST + && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 256 + || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 256) + return 256; /* x86-64 ABI requires arrays greater than 16 bytes to be aligned to 16byte boundary. */ @@ -14107,7 +12798,7 @@ x86_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt) /* Try to load address using shorter movl instead of movabs. We may want to support movq for kernel mode, but kernel does not use trampolines at the moment. */ - if (x86_64_zext_immediate_operand (fnaddr, VOIDmode)) + if (x86_64_zero_extended_value (fnaddr)) { fnaddr = copy_to_mode_reg (DImode, fnaddr); emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)), @@ -14136,459 +12827,24 @@ x86_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt) emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, offset+2)), gen_int_mode (0xe3, QImode)); offset += 3; - gcc_assert (offset <= TRAMPOLINE_SIZE); + if (offset > TRAMPOLINE_SIZE) + abort (); } #ifdef ENABLE_EXECUTE_STACK - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"), + emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"), LCT_NORMAL, VOIDmode, 1, tramp, Pmode); #endif } -/* Codes for all the SSE/MMX builtins. */ -enum ix86_builtins -{ - IX86_BUILTIN_ADDPS, - IX86_BUILTIN_ADDSS, - IX86_BUILTIN_DIVPS, - IX86_BUILTIN_DIVSS, - IX86_BUILTIN_MULPS, - IX86_BUILTIN_MULSS, - IX86_BUILTIN_SUBPS, - IX86_BUILTIN_SUBSS, - - IX86_BUILTIN_CMPEQPS, - IX86_BUILTIN_CMPLTPS, - IX86_BUILTIN_CMPLEPS, - IX86_BUILTIN_CMPGTPS, - IX86_BUILTIN_CMPGEPS, - IX86_BUILTIN_CMPNEQPS, - IX86_BUILTIN_CMPNLTPS, - IX86_BUILTIN_CMPNLEPS, - IX86_BUILTIN_CMPNGTPS, - IX86_BUILTIN_CMPNGEPS, - IX86_BUILTIN_CMPORDPS, - IX86_BUILTIN_CMPUNORDPS, - IX86_BUILTIN_CMPEQSS, - IX86_BUILTIN_CMPLTSS, - IX86_BUILTIN_CMPLESS, - IX86_BUILTIN_CMPNEQSS, - IX86_BUILTIN_CMPNLTSS, - IX86_BUILTIN_CMPNLESS, - IX86_BUILTIN_CMPNGTSS, - IX86_BUILTIN_CMPNGESS, - IX86_BUILTIN_CMPORDSS, - IX86_BUILTIN_CMPUNORDSS, - - IX86_BUILTIN_COMIEQSS, - IX86_BUILTIN_COMILTSS, - IX86_BUILTIN_COMILESS, - IX86_BUILTIN_COMIGTSS, - IX86_BUILTIN_COMIGESS, - IX86_BUILTIN_COMINEQSS, - IX86_BUILTIN_UCOMIEQSS, - IX86_BUILTIN_UCOMILTSS, - IX86_BUILTIN_UCOMILESS, - IX86_BUILTIN_UCOMIGTSS, - IX86_BUILTIN_UCOMIGESS, - IX86_BUILTIN_UCOMINEQSS, - - IX86_BUILTIN_CVTPI2PS, - IX86_BUILTIN_CVTPS2PI, - IX86_BUILTIN_CVTSI2SS, - IX86_BUILTIN_CVTSI642SS, - IX86_BUILTIN_CVTSS2SI, - IX86_BUILTIN_CVTSS2SI64, - IX86_BUILTIN_CVTTPS2PI, - IX86_BUILTIN_CVTTSS2SI, - IX86_BUILTIN_CVTTSS2SI64, - - IX86_BUILTIN_MAXPS, - IX86_BUILTIN_MAXSS, - IX86_BUILTIN_MINPS, - IX86_BUILTIN_MINSS, - - IX86_BUILTIN_LOADUPS, - IX86_BUILTIN_STOREUPS, - IX86_BUILTIN_MOVSS, - - IX86_BUILTIN_MOVHLPS, - IX86_BUILTIN_MOVLHPS, - IX86_BUILTIN_LOADHPS, - IX86_BUILTIN_LOADLPS, - IX86_BUILTIN_STOREHPS, - IX86_BUILTIN_STORELPS, - - IX86_BUILTIN_MASKMOVQ, - IX86_BUILTIN_MOVMSKPS, - IX86_BUILTIN_PMOVMSKB, - - IX86_BUILTIN_MOVNTPS, - IX86_BUILTIN_MOVNTQ, - - IX86_BUILTIN_LOADDQU, - IX86_BUILTIN_STOREDQU, - - IX86_BUILTIN_PACKSSWB, - IX86_BUILTIN_PACKSSDW, - IX86_BUILTIN_PACKUSWB, - - IX86_BUILTIN_PADDB, - IX86_BUILTIN_PADDW, - IX86_BUILTIN_PADDD, - IX86_BUILTIN_PADDQ, - IX86_BUILTIN_PADDSB, - IX86_BUILTIN_PADDSW, - IX86_BUILTIN_PADDUSB, - IX86_BUILTIN_PADDUSW, - IX86_BUILTIN_PSUBB, - IX86_BUILTIN_PSUBW, - IX86_BUILTIN_PSUBD, - IX86_BUILTIN_PSUBQ, - IX86_BUILTIN_PSUBSB, - IX86_BUILTIN_PSUBSW, - IX86_BUILTIN_PSUBUSB, - IX86_BUILTIN_PSUBUSW, - - IX86_BUILTIN_PAND, - IX86_BUILTIN_PANDN, - IX86_BUILTIN_POR, - IX86_BUILTIN_PXOR, - - IX86_BUILTIN_PAVGB, - IX86_BUILTIN_PAVGW, - - IX86_BUILTIN_PCMPEQB, - IX86_BUILTIN_PCMPEQW, - IX86_BUILTIN_PCMPEQD, - IX86_BUILTIN_PCMPGTB, - IX86_BUILTIN_PCMPGTW, - IX86_BUILTIN_PCMPGTD, - - IX86_BUILTIN_PMADDWD, - - IX86_BUILTIN_PMAXSW, - IX86_BUILTIN_PMAXUB, - IX86_BUILTIN_PMINSW, - IX86_BUILTIN_PMINUB, - - IX86_BUILTIN_PMULHUW, - IX86_BUILTIN_PMULHW, - IX86_BUILTIN_PMULLW, - - IX86_BUILTIN_PSADBW, - IX86_BUILTIN_PSHUFW, - - IX86_BUILTIN_PSLLW, - IX86_BUILTIN_PSLLD, - IX86_BUILTIN_PSLLQ, - IX86_BUILTIN_PSRAW, - IX86_BUILTIN_PSRAD, - IX86_BUILTIN_PSRLW, - IX86_BUILTIN_PSRLD, - IX86_BUILTIN_PSRLQ, - IX86_BUILTIN_PSLLWI, - IX86_BUILTIN_PSLLDI, - IX86_BUILTIN_PSLLQI, - IX86_BUILTIN_PSRAWI, - IX86_BUILTIN_PSRADI, - IX86_BUILTIN_PSRLWI, - IX86_BUILTIN_PSRLDI, - IX86_BUILTIN_PSRLQI, - - IX86_BUILTIN_PUNPCKHBW, - IX86_BUILTIN_PUNPCKHWD, - IX86_BUILTIN_PUNPCKHDQ, - IX86_BUILTIN_PUNPCKLBW, - IX86_BUILTIN_PUNPCKLWD, - IX86_BUILTIN_PUNPCKLDQ, - - IX86_BUILTIN_SHUFPS, - - IX86_BUILTIN_RCPPS, - IX86_BUILTIN_RCPSS, - IX86_BUILTIN_RSQRTPS, - IX86_BUILTIN_RSQRTSS, - IX86_BUILTIN_SQRTPS, - IX86_BUILTIN_SQRTSS, - - IX86_BUILTIN_UNPCKHPS, - IX86_BUILTIN_UNPCKLPS, - - IX86_BUILTIN_ANDPS, - IX86_BUILTIN_ANDNPS, - IX86_BUILTIN_ORPS, - IX86_BUILTIN_XORPS, - - IX86_BUILTIN_EMMS, - IX86_BUILTIN_LDMXCSR, - IX86_BUILTIN_STMXCSR, - IX86_BUILTIN_SFENCE, - - /* 3DNow! Original */ - IX86_BUILTIN_FEMMS, - IX86_BUILTIN_PAVGUSB, - IX86_BUILTIN_PF2ID, - IX86_BUILTIN_PFACC, - IX86_BUILTIN_PFADD, - IX86_BUILTIN_PFCMPEQ, - IX86_BUILTIN_PFCMPGE, - IX86_BUILTIN_PFCMPGT, - IX86_BUILTIN_PFMAX, - IX86_BUILTIN_PFMIN, - IX86_BUILTIN_PFMUL, - IX86_BUILTIN_PFRCP, - IX86_BUILTIN_PFRCPIT1, - IX86_BUILTIN_PFRCPIT2, - IX86_BUILTIN_PFRSQIT1, - IX86_BUILTIN_PFRSQRT, - IX86_BUILTIN_PFSUB, - IX86_BUILTIN_PFSUBR, - IX86_BUILTIN_PI2FD, - IX86_BUILTIN_PMULHRW, - - /* 3DNow! Athlon Extensions */ - IX86_BUILTIN_PF2IW, - IX86_BUILTIN_PFNACC, - IX86_BUILTIN_PFPNACC, - IX86_BUILTIN_PI2FW, - IX86_BUILTIN_PSWAPDSI, - IX86_BUILTIN_PSWAPDSF, - - /* SSE2 */ - IX86_BUILTIN_ADDPD, - IX86_BUILTIN_ADDSD, - IX86_BUILTIN_DIVPD, - IX86_BUILTIN_DIVSD, - IX86_BUILTIN_MULPD, - IX86_BUILTIN_MULSD, - IX86_BUILTIN_SUBPD, - IX86_BUILTIN_SUBSD, - - IX86_BUILTIN_CMPEQPD, - IX86_BUILTIN_CMPLTPD, - IX86_BUILTIN_CMPLEPD, - IX86_BUILTIN_CMPGTPD, - IX86_BUILTIN_CMPGEPD, - IX86_BUILTIN_CMPNEQPD, - IX86_BUILTIN_CMPNLTPD, - IX86_BUILTIN_CMPNLEPD, - IX86_BUILTIN_CMPNGTPD, - IX86_BUILTIN_CMPNGEPD, - IX86_BUILTIN_CMPORDPD, - IX86_BUILTIN_CMPUNORDPD, - IX86_BUILTIN_CMPNEPD, - IX86_BUILTIN_CMPEQSD, - IX86_BUILTIN_CMPLTSD, - IX86_BUILTIN_CMPLESD, - IX86_BUILTIN_CMPNEQSD, - IX86_BUILTIN_CMPNLTSD, - IX86_BUILTIN_CMPNLESD, - IX86_BUILTIN_CMPORDSD, - IX86_BUILTIN_CMPUNORDSD, - IX86_BUILTIN_CMPNESD, - - IX86_BUILTIN_COMIEQSD, - IX86_BUILTIN_COMILTSD, - IX86_BUILTIN_COMILESD, - IX86_BUILTIN_COMIGTSD, - IX86_BUILTIN_COMIGESD, - IX86_BUILTIN_COMINEQSD, - IX86_BUILTIN_UCOMIEQSD, - IX86_BUILTIN_UCOMILTSD, - IX86_BUILTIN_UCOMILESD, - IX86_BUILTIN_UCOMIGTSD, - IX86_BUILTIN_UCOMIGESD, - IX86_BUILTIN_UCOMINEQSD, - - IX86_BUILTIN_MAXPD, - IX86_BUILTIN_MAXSD, - IX86_BUILTIN_MINPD, - IX86_BUILTIN_MINSD, - - IX86_BUILTIN_ANDPD, - IX86_BUILTIN_ANDNPD, - IX86_BUILTIN_ORPD, - IX86_BUILTIN_XORPD, - - IX86_BUILTIN_SQRTPD, - IX86_BUILTIN_SQRTSD, - - IX86_BUILTIN_UNPCKHPD, - IX86_BUILTIN_UNPCKLPD, - - IX86_BUILTIN_SHUFPD, - - IX86_BUILTIN_LOADUPD, - IX86_BUILTIN_STOREUPD, - IX86_BUILTIN_MOVSD, - - IX86_BUILTIN_LOADHPD, - IX86_BUILTIN_LOADLPD, - - IX86_BUILTIN_CVTDQ2PD, - IX86_BUILTIN_CVTDQ2PS, - - IX86_BUILTIN_CVTPD2DQ, - IX86_BUILTIN_CVTPD2PI, - IX86_BUILTIN_CVTPD2PS, - IX86_BUILTIN_CVTTPD2DQ, - IX86_BUILTIN_CVTTPD2PI, - - IX86_BUILTIN_CVTPI2PD, - IX86_BUILTIN_CVTSI2SD, - IX86_BUILTIN_CVTSI642SD, - - IX86_BUILTIN_CVTSD2SI, - IX86_BUILTIN_CVTSD2SI64, - IX86_BUILTIN_CVTSD2SS, - IX86_BUILTIN_CVTSS2SD, - IX86_BUILTIN_CVTTSD2SI, - IX86_BUILTIN_CVTTSD2SI64, - - IX86_BUILTIN_CVTPS2DQ, - IX86_BUILTIN_CVTPS2PD, - IX86_BUILTIN_CVTTPS2DQ, - - IX86_BUILTIN_MOVNTI, - IX86_BUILTIN_MOVNTPD, - IX86_BUILTIN_MOVNTDQ, - - /* SSE2 MMX */ - IX86_BUILTIN_MASKMOVDQU, - IX86_BUILTIN_MOVMSKPD, - IX86_BUILTIN_PMOVMSKB128, - - IX86_BUILTIN_PACKSSWB128, - IX86_BUILTIN_PACKSSDW128, - IX86_BUILTIN_PACKUSWB128, - - IX86_BUILTIN_PADDB128, - IX86_BUILTIN_PADDW128, - IX86_BUILTIN_PADDD128, - IX86_BUILTIN_PADDQ128, - IX86_BUILTIN_PADDSB128, - IX86_BUILTIN_PADDSW128, - IX86_BUILTIN_PADDUSB128, - IX86_BUILTIN_PADDUSW128, - IX86_BUILTIN_PSUBB128, - IX86_BUILTIN_PSUBW128, - IX86_BUILTIN_PSUBD128, - IX86_BUILTIN_PSUBQ128, - IX86_BUILTIN_PSUBSB128, - IX86_BUILTIN_PSUBSW128, - IX86_BUILTIN_PSUBUSB128, - IX86_BUILTIN_PSUBUSW128, - - IX86_BUILTIN_PAND128, - IX86_BUILTIN_PANDN128, - IX86_BUILTIN_POR128, - IX86_BUILTIN_PXOR128, - - IX86_BUILTIN_PAVGB128, - IX86_BUILTIN_PAVGW128, - - IX86_BUILTIN_PCMPEQB128, - IX86_BUILTIN_PCMPEQW128, - IX86_BUILTIN_PCMPEQD128, - IX86_BUILTIN_PCMPGTB128, - IX86_BUILTIN_PCMPGTW128, - IX86_BUILTIN_PCMPGTD128, - - IX86_BUILTIN_PMADDWD128, - - IX86_BUILTIN_PMAXSW128, - IX86_BUILTIN_PMAXUB128, - IX86_BUILTIN_PMINSW128, - IX86_BUILTIN_PMINUB128, - - IX86_BUILTIN_PMULUDQ, - IX86_BUILTIN_PMULUDQ128, - IX86_BUILTIN_PMULHUW128, - IX86_BUILTIN_PMULHW128, - IX86_BUILTIN_PMULLW128, - - IX86_BUILTIN_PSADBW128, - IX86_BUILTIN_PSHUFHW, - IX86_BUILTIN_PSHUFLW, - IX86_BUILTIN_PSHUFD, - - IX86_BUILTIN_PSLLW128, - IX86_BUILTIN_PSLLD128, - IX86_BUILTIN_PSLLQ128, - IX86_BUILTIN_PSRAW128, - IX86_BUILTIN_PSRAD128, - IX86_BUILTIN_PSRLW128, - IX86_BUILTIN_PSRLD128, - IX86_BUILTIN_PSRLQ128, - IX86_BUILTIN_PSLLDQI128, - IX86_BUILTIN_PSLLWI128, - IX86_BUILTIN_PSLLDI128, - IX86_BUILTIN_PSLLQI128, - IX86_BUILTIN_PSRAWI128, - IX86_BUILTIN_PSRADI128, - IX86_BUILTIN_PSRLDQI128, - IX86_BUILTIN_PSRLWI128, - IX86_BUILTIN_PSRLDI128, - IX86_BUILTIN_PSRLQI128, - - IX86_BUILTIN_PUNPCKHBW128, - IX86_BUILTIN_PUNPCKHWD128, - IX86_BUILTIN_PUNPCKHDQ128, - IX86_BUILTIN_PUNPCKHQDQ128, - IX86_BUILTIN_PUNPCKLBW128, - IX86_BUILTIN_PUNPCKLWD128, - IX86_BUILTIN_PUNPCKLDQ128, - IX86_BUILTIN_PUNPCKLQDQ128, - - IX86_BUILTIN_CLFLUSH, - IX86_BUILTIN_MFENCE, - IX86_BUILTIN_LFENCE, - - /* Prescott New Instructions. */ - IX86_BUILTIN_ADDSUBPS, - IX86_BUILTIN_HADDPS, - IX86_BUILTIN_HSUBPS, - IX86_BUILTIN_MOVSHDUP, - IX86_BUILTIN_MOVSLDUP, - IX86_BUILTIN_ADDSUBPD, - IX86_BUILTIN_HADDPD, - IX86_BUILTIN_HSUBPD, - IX86_BUILTIN_LDDQU, - - IX86_BUILTIN_MONITOR, - IX86_BUILTIN_MWAIT, - - IX86_BUILTIN_VEC_INIT_V2SI, - IX86_BUILTIN_VEC_INIT_V4HI, - IX86_BUILTIN_VEC_INIT_V8QI, - IX86_BUILTIN_VEC_EXT_V2DF, - IX86_BUILTIN_VEC_EXT_V2DI, - IX86_BUILTIN_VEC_EXT_V4SF, - IX86_BUILTIN_VEC_EXT_V4SI, - IX86_BUILTIN_VEC_EXT_V8HI, - IX86_BUILTIN_VEC_EXT_V2SI, - IX86_BUILTIN_VEC_EXT_V4HI, - IX86_BUILTIN_VEC_SET_V8HI, - IX86_BUILTIN_VEC_SET_V4HI, - - IX86_BUILTIN_MAX -}; - -#define def_builtin(MASK, NAME, TYPE, CODE) \ -do { \ - if ((MASK) & target_flags \ - && (!((MASK) & MASK_64BIT) || TARGET_64BIT)) \ - lang_hooks.builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \ - NULL, NULL_TREE); \ +#define def_builtin(MASK, NAME, TYPE, CODE) \ +do { \ + if ((MASK) & target_flags \ + && (!((MASK) & MASK_64BIT) || TARGET_64BIT)) \ + builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \ + NULL, NULL_TREE); \ } while (0) -/* Bits for builtin_description.flag. */ - -/* Set when we don't support the comparison natively, and should - swap_comparison in order to support it. */ -#define BUILTIN_DESC_SWAP_OPERANDS 1 - struct builtin_description { const unsigned int mask; @@ -14634,49 +12890,41 @@ static const struct builtin_description bdesc_2arg[] = { MASK_SSE, CODE_FOR_subv4sf3, "__builtin_ia32_subps", IX86_BUILTIN_SUBPS, 0, 0 }, { MASK_SSE, CODE_FOR_mulv4sf3, "__builtin_ia32_mulps", IX86_BUILTIN_MULPS, 0, 0 }, { MASK_SSE, CODE_FOR_divv4sf3, "__builtin_ia32_divps", IX86_BUILTIN_DIVPS, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_vmaddv4sf3, "__builtin_ia32_addss", IX86_BUILTIN_ADDSS, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_vmsubv4sf3, "__builtin_ia32_subss", IX86_BUILTIN_SUBSS, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_vmmulv4sf3, "__builtin_ia32_mulss", IX86_BUILTIN_MULSS, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_vmdivv4sf3, "__builtin_ia32_divss", IX86_BUILTIN_DIVSS, 0, 0 }, - - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpeqps", IX86_BUILTIN_CMPEQPS, EQ, 0 }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpltps", IX86_BUILTIN_CMPLTPS, LT, 0 }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpleps", IX86_BUILTIN_CMPLEPS, LE, 0 }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpgtps", IX86_BUILTIN_CMPGTPS, LT, - BUILTIN_DESC_SWAP_OPERANDS }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpgeps", IX86_BUILTIN_CMPGEPS, LE, - BUILTIN_DESC_SWAP_OPERANDS }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpunordps", IX86_BUILTIN_CMPUNORDPS, UNORDERED, 0 }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpneqps", IX86_BUILTIN_CMPNEQPS, NE, 0 }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpnltps", IX86_BUILTIN_CMPNLTPS, UNGE, 0 }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpnleps", IX86_BUILTIN_CMPNLEPS, UNGT, 0 }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpngtps", IX86_BUILTIN_CMPNGTPS, UNGE, - BUILTIN_DESC_SWAP_OPERANDS }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpngeps", IX86_BUILTIN_CMPNGEPS, UNGT, - BUILTIN_DESC_SWAP_OPERANDS }, - { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpordps", IX86_BUILTIN_CMPORDPS, ORDERED, 0 }, - { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpeqss", IX86_BUILTIN_CMPEQSS, EQ, 0 }, - { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpltss", IX86_BUILTIN_CMPLTSS, LT, 0 }, - { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpless", IX86_BUILTIN_CMPLESS, LE, 0 }, - { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpunordss", IX86_BUILTIN_CMPUNORDSS, UNORDERED, 0 }, - { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpneqss", IX86_BUILTIN_CMPNEQSS, NE, 0 }, - { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpnltss", IX86_BUILTIN_CMPNLTSS, UNGE, 0 }, - { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpnless", IX86_BUILTIN_CMPNLESS, UNGT, 0 }, - { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpngtss", IX86_BUILTIN_CMPNGTSS, UNGE, - BUILTIN_DESC_SWAP_OPERANDS }, - { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpngess", IX86_BUILTIN_CMPNGESS, UNGT, - BUILTIN_DESC_SWAP_OPERANDS }, - { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpordss", IX86_BUILTIN_CMPORDSS, ORDERED, 0 }, + { MASK_SSE, CODE_FOR_vmaddv4sf3, "__builtin_ia32_addss", IX86_BUILTIN_ADDSS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmsubv4sf3, "__builtin_ia32_subss", IX86_BUILTIN_SUBSS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmmulv4sf3, "__builtin_ia32_mulss", IX86_BUILTIN_MULSS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmdivv4sf3, "__builtin_ia32_divss", IX86_BUILTIN_DIVSS, 0, 0 }, + + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpeqps", IX86_BUILTIN_CMPEQPS, EQ, 0 }, + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpltps", IX86_BUILTIN_CMPLTPS, LT, 0 }, + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpleps", IX86_BUILTIN_CMPLEPS, LE, 0 }, + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpgtps", IX86_BUILTIN_CMPGTPS, LT, 1 }, + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpgeps", IX86_BUILTIN_CMPGEPS, LE, 1 }, + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpunordps", IX86_BUILTIN_CMPUNORDPS, UNORDERED, 0 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpneqps", IX86_BUILTIN_CMPNEQPS, EQ, 0 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpnltps", IX86_BUILTIN_CMPNLTPS, LT, 0 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpnleps", IX86_BUILTIN_CMPNLEPS, LE, 0 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpngtps", IX86_BUILTIN_CMPNGTPS, LT, 1 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpngeps", IX86_BUILTIN_CMPNGEPS, LE, 1 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpordps", IX86_BUILTIN_CMPORDPS, UNORDERED, 0 }, + { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpeqss", IX86_BUILTIN_CMPEQSS, EQ, 0 }, + { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpltss", IX86_BUILTIN_CMPLTSS, LT, 0 }, + { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpless", IX86_BUILTIN_CMPLESS, LE, 0 }, + { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpunordss", IX86_BUILTIN_CMPUNORDSS, UNORDERED, 0 }, + { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpneqss", IX86_BUILTIN_CMPNEQSS, EQ, 0 }, + { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpnltss", IX86_BUILTIN_CMPNLTSS, LT, 0 }, + { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpnless", IX86_BUILTIN_CMPNLESS, LE, 0 }, + { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpordss", IX86_BUILTIN_CMPORDSS, UNORDERED, 0 }, { MASK_SSE, CODE_FOR_sminv4sf3, "__builtin_ia32_minps", IX86_BUILTIN_MINPS, 0, 0 }, { MASK_SSE, CODE_FOR_smaxv4sf3, "__builtin_ia32_maxps", IX86_BUILTIN_MAXPS, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_vmsminv4sf3, "__builtin_ia32_minss", IX86_BUILTIN_MINSS, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_vmsmaxv4sf3, "__builtin_ia32_maxss", IX86_BUILTIN_MAXSS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmsminv4sf3, "__builtin_ia32_minss", IX86_BUILTIN_MINSS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmsmaxv4sf3, "__builtin_ia32_maxss", IX86_BUILTIN_MAXSS, 0, 0 }, - { MASK_SSE, CODE_FOR_andv4sf3, "__builtin_ia32_andps", IX86_BUILTIN_ANDPS, 0, 0 }, + { MASK_SSE, CODE_FOR_sse_andv4sf3, "__builtin_ia32_andps", IX86_BUILTIN_ANDPS, 0, 0 }, { MASK_SSE, CODE_FOR_sse_nandv4sf3, "__builtin_ia32_andnps", IX86_BUILTIN_ANDNPS, 0, 0 }, - { MASK_SSE, CODE_FOR_iorv4sf3, "__builtin_ia32_orps", IX86_BUILTIN_ORPS, 0, 0 }, - { MASK_SSE, CODE_FOR_xorv4sf3, "__builtin_ia32_xorps", IX86_BUILTIN_XORPS, 0, 0 }, + { MASK_SSE, CODE_FOR_sse_iorv4sf3, "__builtin_ia32_orps", IX86_BUILTIN_ORPS, 0, 0 }, + { MASK_SSE, CODE_FOR_sse_xorv4sf3, "__builtin_ia32_xorps", IX86_BUILTIN_XORPS, 0, 0 }, { MASK_SSE, CODE_FOR_sse_movss, "__builtin_ia32_movss", IX86_BUILTIN_MOVSS, 0, 0 }, { MASK_SSE, CODE_FOR_sse_movhlps, "__builtin_ia32_movhlps", IX86_BUILTIN_MOVHLPS, 0, 0 }, @@ -14685,47 +12933,47 @@ static const struct builtin_description bdesc_2arg[] = { MASK_SSE, CODE_FOR_sse_unpcklps, "__builtin_ia32_unpcklps", IX86_BUILTIN_UNPCKLPS, 0, 0 }, /* MMX */ - { MASK_MMX, CODE_FOR_mmx_addv8qi3, "__builtin_ia32_paddb", IX86_BUILTIN_PADDB, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_addv4hi3, "__builtin_ia32_paddw", IX86_BUILTIN_PADDW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_addv2si3, "__builtin_ia32_paddd", IX86_BUILTIN_PADDD, 0, 0 }, - { MASK_SSE2, CODE_FOR_mmx_adddi3, "__builtin_ia32_paddq", IX86_BUILTIN_PADDQ, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_subv8qi3, "__builtin_ia32_psubb", IX86_BUILTIN_PSUBB, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_subv4hi3, "__builtin_ia32_psubw", IX86_BUILTIN_PSUBW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_subv2si3, "__builtin_ia32_psubd", IX86_BUILTIN_PSUBD, 0, 0 }, - { MASK_SSE2, CODE_FOR_mmx_subdi3, "__builtin_ia32_psubq", IX86_BUILTIN_PSUBQ, 0, 0 }, - - { MASK_MMX, CODE_FOR_mmx_ssaddv8qi3, "__builtin_ia32_paddsb", IX86_BUILTIN_PADDSB, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ssaddv4hi3, "__builtin_ia32_paddsw", IX86_BUILTIN_PADDSW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_sssubv8qi3, "__builtin_ia32_psubsb", IX86_BUILTIN_PSUBSB, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_sssubv4hi3, "__builtin_ia32_psubsw", IX86_BUILTIN_PSUBSW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_usaddv8qi3, "__builtin_ia32_paddusb", IX86_BUILTIN_PADDUSB, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_usaddv4hi3, "__builtin_ia32_paddusw", IX86_BUILTIN_PADDUSW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ussubv8qi3, "__builtin_ia32_psubusb", IX86_BUILTIN_PSUBUSB, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ussubv4hi3, "__builtin_ia32_psubusw", IX86_BUILTIN_PSUBUSW, 0, 0 }, - - { MASK_MMX, CODE_FOR_mmx_mulv4hi3, "__builtin_ia32_pmullw", IX86_BUILTIN_PMULLW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_smulv4hi3_highpart, "__builtin_ia32_pmulhw", IX86_BUILTIN_PMULHW, 0, 0 }, - { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_umulv4hi3_highpart, "__builtin_ia32_pmulhuw", IX86_BUILTIN_PMULHUW, 0, 0 }, - - { MASK_MMX, CODE_FOR_mmx_andv2si3, "__builtin_ia32_pand", IX86_BUILTIN_PAND, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_nandv2si3, "__builtin_ia32_pandn", IX86_BUILTIN_PANDN, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_iorv2si3, "__builtin_ia32_por", IX86_BUILTIN_POR, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_xorv2si3, "__builtin_ia32_pxor", IX86_BUILTIN_PXOR, 0, 0 }, + { MASK_MMX, CODE_FOR_addv8qi3, "__builtin_ia32_paddb", IX86_BUILTIN_PADDB, 0, 0 }, + { MASK_MMX, CODE_FOR_addv4hi3, "__builtin_ia32_paddw", IX86_BUILTIN_PADDW, 0, 0 }, + { MASK_MMX, CODE_FOR_addv2si3, "__builtin_ia32_paddd", IX86_BUILTIN_PADDD, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_adddi3, "__builtin_ia32_paddq", IX86_BUILTIN_PADDQ, 0, 0 }, + { MASK_MMX, CODE_FOR_subv8qi3, "__builtin_ia32_psubb", IX86_BUILTIN_PSUBB, 0, 0 }, + { MASK_MMX, CODE_FOR_subv4hi3, "__builtin_ia32_psubw", IX86_BUILTIN_PSUBW, 0, 0 }, + { MASK_MMX, CODE_FOR_subv2si3, "__builtin_ia32_psubd", IX86_BUILTIN_PSUBD, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_subdi3, "__builtin_ia32_psubq", IX86_BUILTIN_PSUBQ, 0, 0 }, + + { MASK_MMX, CODE_FOR_ssaddv8qi3, "__builtin_ia32_paddsb", IX86_BUILTIN_PADDSB, 0, 0 }, + { MASK_MMX, CODE_FOR_ssaddv4hi3, "__builtin_ia32_paddsw", IX86_BUILTIN_PADDSW, 0, 0 }, + { MASK_MMX, CODE_FOR_sssubv8qi3, "__builtin_ia32_psubsb", IX86_BUILTIN_PSUBSB, 0, 0 }, + { MASK_MMX, CODE_FOR_sssubv4hi3, "__builtin_ia32_psubsw", IX86_BUILTIN_PSUBSW, 0, 0 }, + { MASK_MMX, CODE_FOR_usaddv8qi3, "__builtin_ia32_paddusb", IX86_BUILTIN_PADDUSB, 0, 0 }, + { MASK_MMX, CODE_FOR_usaddv4hi3, "__builtin_ia32_paddusw", IX86_BUILTIN_PADDUSW, 0, 0 }, + { MASK_MMX, CODE_FOR_ussubv8qi3, "__builtin_ia32_psubusb", IX86_BUILTIN_PSUBUSB, 0, 0 }, + { MASK_MMX, CODE_FOR_ussubv4hi3, "__builtin_ia32_psubusw", IX86_BUILTIN_PSUBUSW, 0, 0 }, + + { MASK_MMX, CODE_FOR_mulv4hi3, "__builtin_ia32_pmullw", IX86_BUILTIN_PMULLW, 0, 0 }, + { MASK_MMX, CODE_FOR_smulv4hi3_highpart, "__builtin_ia32_pmulhw", IX86_BUILTIN_PMULHW, 0, 0 }, + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_umulv4hi3_highpart, "__builtin_ia32_pmulhuw", IX86_BUILTIN_PMULHUW, 0, 0 }, + + { MASK_MMX, CODE_FOR_mmx_anddi3, "__builtin_ia32_pand", IX86_BUILTIN_PAND, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_nanddi3, "__builtin_ia32_pandn", IX86_BUILTIN_PANDN, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_iordi3, "__builtin_ia32_por", IX86_BUILTIN_POR, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_xordi3, "__builtin_ia32_pxor", IX86_BUILTIN_PXOR, 0, 0 }, { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_uavgv8qi3, "__builtin_ia32_pavgb", IX86_BUILTIN_PAVGB, 0, 0 }, { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_uavgv4hi3, "__builtin_ia32_pavgw", IX86_BUILTIN_PAVGW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_eqv8qi3, "__builtin_ia32_pcmpeqb", IX86_BUILTIN_PCMPEQB, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_eqv4hi3, "__builtin_ia32_pcmpeqw", IX86_BUILTIN_PCMPEQW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_eqv2si3, "__builtin_ia32_pcmpeqd", IX86_BUILTIN_PCMPEQD, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_gtv8qi3, "__builtin_ia32_pcmpgtb", IX86_BUILTIN_PCMPGTB, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_gtv4hi3, "__builtin_ia32_pcmpgtw", IX86_BUILTIN_PCMPGTW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_gtv2si3, "__builtin_ia32_pcmpgtd", IX86_BUILTIN_PCMPGTD, 0, 0 }, + { MASK_MMX, CODE_FOR_eqv8qi3, "__builtin_ia32_pcmpeqb", IX86_BUILTIN_PCMPEQB, 0, 0 }, + { MASK_MMX, CODE_FOR_eqv4hi3, "__builtin_ia32_pcmpeqw", IX86_BUILTIN_PCMPEQW, 0, 0 }, + { MASK_MMX, CODE_FOR_eqv2si3, "__builtin_ia32_pcmpeqd", IX86_BUILTIN_PCMPEQD, 0, 0 }, + { MASK_MMX, CODE_FOR_gtv8qi3, "__builtin_ia32_pcmpgtb", IX86_BUILTIN_PCMPGTB, 0, 0 }, + { MASK_MMX, CODE_FOR_gtv4hi3, "__builtin_ia32_pcmpgtw", IX86_BUILTIN_PCMPGTW, 0, 0 }, + { MASK_MMX, CODE_FOR_gtv2si3, "__builtin_ia32_pcmpgtd", IX86_BUILTIN_PCMPGTD, 0, 0 }, - { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_umaxv8qi3, "__builtin_ia32_pmaxub", IX86_BUILTIN_PMAXUB, 0, 0 }, - { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_smaxv4hi3, "__builtin_ia32_pmaxsw", IX86_BUILTIN_PMAXSW, 0, 0 }, - { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_uminv8qi3, "__builtin_ia32_pminub", IX86_BUILTIN_PMINUB, 0, 0 }, - { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_sminv4hi3, "__builtin_ia32_pminsw", IX86_BUILTIN_PMINSW, 0, 0 }, + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_umaxv8qi3, "__builtin_ia32_pmaxub", IX86_BUILTIN_PMAXUB, 0, 0 }, + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_smaxv4hi3, "__builtin_ia32_pmaxsw", IX86_BUILTIN_PMAXSW, 0, 0 }, + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_uminv8qi3, "__builtin_ia32_pminub", IX86_BUILTIN_PMINUB, 0, 0 }, + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_sminv4hi3, "__builtin_ia32_pminsw", IX86_BUILTIN_PMINSW, 0, 0 }, { MASK_MMX, CODE_FOR_mmx_punpckhbw, "__builtin_ia32_punpckhbw", IX86_BUILTIN_PUNPCKHBW, 0, 0 }, { MASK_MMX, CODE_FOR_mmx_punpckhwd, "__builtin_ia32_punpckhwd", IX86_BUILTIN_PUNPCKHWD, 0, 0 }, @@ -14739,28 +12987,28 @@ static const struct builtin_description bdesc_2arg[] = { MASK_MMX, CODE_FOR_mmx_packssdw, 0, IX86_BUILTIN_PACKSSDW, 0, 0 }, { MASK_MMX, CODE_FOR_mmx_packuswb, 0, IX86_BUILTIN_PACKUSWB, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_cvtpi2ps, 0, IX86_BUILTIN_CVTPI2PS, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_cvtsi2ss, 0, IX86_BUILTIN_CVTSI2SS, 0, 0 }, - { MASK_SSE | MASK_64BIT, CODE_FOR_sse_cvtsi2ssq, 0, IX86_BUILTIN_CVTSI642SS, 0, 0 }, + { MASK_SSE, CODE_FOR_cvtpi2ps, 0, IX86_BUILTIN_CVTPI2PS, 0, 0 }, + { MASK_SSE, CODE_FOR_cvtsi2ss, 0, IX86_BUILTIN_CVTSI2SS, 0, 0 }, + { MASK_SSE | MASK_64BIT, CODE_FOR_cvtsi2ssq, 0, IX86_BUILTIN_CVTSI642SS, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ashlv4hi3, 0, IX86_BUILTIN_PSLLW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ashlv4hi3, 0, IX86_BUILTIN_PSLLWI, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ashlv2si3, 0, IX86_BUILTIN_PSLLD, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ashlv2si3, 0, IX86_BUILTIN_PSLLDI, 0, 0 }, + { MASK_MMX, CODE_FOR_ashlv4hi3, 0, IX86_BUILTIN_PSLLW, 0, 0 }, + { MASK_MMX, CODE_FOR_ashlv4hi3, 0, IX86_BUILTIN_PSLLWI, 0, 0 }, + { MASK_MMX, CODE_FOR_ashlv2si3, 0, IX86_BUILTIN_PSLLD, 0, 0 }, + { MASK_MMX, CODE_FOR_ashlv2si3, 0, IX86_BUILTIN_PSLLDI, 0, 0 }, { MASK_MMX, CODE_FOR_mmx_ashldi3, 0, IX86_BUILTIN_PSLLQ, 0, 0 }, { MASK_MMX, CODE_FOR_mmx_ashldi3, 0, IX86_BUILTIN_PSLLQI, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_lshrv4hi3, 0, IX86_BUILTIN_PSRLW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_lshrv4hi3, 0, IX86_BUILTIN_PSRLWI, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_lshrv2si3, 0, IX86_BUILTIN_PSRLD, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_lshrv2si3, 0, IX86_BUILTIN_PSRLDI, 0, 0 }, + { MASK_MMX, CODE_FOR_lshrv4hi3, 0, IX86_BUILTIN_PSRLW, 0, 0 }, + { MASK_MMX, CODE_FOR_lshrv4hi3, 0, IX86_BUILTIN_PSRLWI, 0, 0 }, + { MASK_MMX, CODE_FOR_lshrv2si3, 0, IX86_BUILTIN_PSRLD, 0, 0 }, + { MASK_MMX, CODE_FOR_lshrv2si3, 0, IX86_BUILTIN_PSRLDI, 0, 0 }, { MASK_MMX, CODE_FOR_mmx_lshrdi3, 0, IX86_BUILTIN_PSRLQ, 0, 0 }, { MASK_MMX, CODE_FOR_mmx_lshrdi3, 0, IX86_BUILTIN_PSRLQI, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ashrv4hi3, 0, IX86_BUILTIN_PSRAW, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ashrv4hi3, 0, IX86_BUILTIN_PSRAWI, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ashrv2si3, 0, IX86_BUILTIN_PSRAD, 0, 0 }, - { MASK_MMX, CODE_FOR_mmx_ashrv2si3, 0, IX86_BUILTIN_PSRADI, 0, 0 }, + { MASK_MMX, CODE_FOR_ashrv4hi3, 0, IX86_BUILTIN_PSRAW, 0, 0 }, + { MASK_MMX, CODE_FOR_ashrv4hi3, 0, IX86_BUILTIN_PSRAWI, 0, 0 }, + { MASK_MMX, CODE_FOR_ashrv2si3, 0, IX86_BUILTIN_PSRAD, 0, 0 }, + { MASK_MMX, CODE_FOR_ashrv2si3, 0, IX86_BUILTIN_PSRADI, 0, 0 }, { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_psadbw, 0, IX86_BUILTIN_PSADBW, 0, 0 }, { MASK_MMX, CODE_FOR_mmx_pmaddwd, 0, IX86_BUILTIN_PMADDWD, 0, 0 }, @@ -14770,45 +13018,41 @@ static const struct builtin_description bdesc_2arg[] = { MASK_SSE2, CODE_FOR_subv2df3, "__builtin_ia32_subpd", IX86_BUILTIN_SUBPD, 0, 0 }, { MASK_SSE2, CODE_FOR_mulv2df3, "__builtin_ia32_mulpd", IX86_BUILTIN_MULPD, 0, 0 }, { MASK_SSE2, CODE_FOR_divv2df3, "__builtin_ia32_divpd", IX86_BUILTIN_DIVPD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmaddv2df3, "__builtin_ia32_addsd", IX86_BUILTIN_ADDSD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmsubv2df3, "__builtin_ia32_subsd", IX86_BUILTIN_SUBSD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmmulv2df3, "__builtin_ia32_mulsd", IX86_BUILTIN_MULSD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmdivv2df3, "__builtin_ia32_divsd", IX86_BUILTIN_DIVSD, 0, 0 }, - - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpeqpd", IX86_BUILTIN_CMPEQPD, EQ, 0 }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpltpd", IX86_BUILTIN_CMPLTPD, LT, 0 }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmplepd", IX86_BUILTIN_CMPLEPD, LE, 0 }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpgtpd", IX86_BUILTIN_CMPGTPD, LT, - BUILTIN_DESC_SWAP_OPERANDS }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpgepd", IX86_BUILTIN_CMPGEPD, LE, - BUILTIN_DESC_SWAP_OPERANDS }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpunordpd", IX86_BUILTIN_CMPUNORDPD, UNORDERED, 0 }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpneqpd", IX86_BUILTIN_CMPNEQPD, NE, 0 }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpnltpd", IX86_BUILTIN_CMPNLTPD, UNGE, 0 }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpnlepd", IX86_BUILTIN_CMPNLEPD, UNGT, 0 }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpngtpd", IX86_BUILTIN_CMPNGTPD, UNGE, - BUILTIN_DESC_SWAP_OPERANDS }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpngepd", IX86_BUILTIN_CMPNGEPD, UNGT, - BUILTIN_DESC_SWAP_OPERANDS }, - { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpordpd", IX86_BUILTIN_CMPORDPD, ORDERED, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpeqsd", IX86_BUILTIN_CMPEQSD, EQ, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpltsd", IX86_BUILTIN_CMPLTSD, LT, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmplesd", IX86_BUILTIN_CMPLESD, LE, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpunordsd", IX86_BUILTIN_CMPUNORDSD, UNORDERED, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpneqsd", IX86_BUILTIN_CMPNEQSD, NE, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpnltsd", IX86_BUILTIN_CMPNLTSD, UNGE, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpnlesd", IX86_BUILTIN_CMPNLESD, UNGT, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpordsd", IX86_BUILTIN_CMPORDSD, ORDERED, 0 }, + { MASK_SSE2, CODE_FOR_vmaddv2df3, "__builtin_ia32_addsd", IX86_BUILTIN_ADDSD, 0, 0 }, + { MASK_SSE2, CODE_FOR_vmsubv2df3, "__builtin_ia32_subsd", IX86_BUILTIN_SUBSD, 0, 0 }, + { MASK_SSE2, CODE_FOR_vmmulv2df3, "__builtin_ia32_mulsd", IX86_BUILTIN_MULSD, 0, 0 }, + { MASK_SSE2, CODE_FOR_vmdivv2df3, "__builtin_ia32_divsd", IX86_BUILTIN_DIVSD, 0, 0 }, + + { MASK_SSE2, CODE_FOR_maskcmpv2df3, "__builtin_ia32_cmpeqpd", IX86_BUILTIN_CMPEQPD, EQ, 0 }, + { MASK_SSE2, CODE_FOR_maskcmpv2df3, "__builtin_ia32_cmpltpd", IX86_BUILTIN_CMPLTPD, LT, 0 }, + { MASK_SSE2, CODE_FOR_maskcmpv2df3, "__builtin_ia32_cmplepd", IX86_BUILTIN_CMPLEPD, LE, 0 }, + { MASK_SSE2, CODE_FOR_maskcmpv2df3, "__builtin_ia32_cmpgtpd", IX86_BUILTIN_CMPGTPD, LT, 1 }, + { MASK_SSE2, CODE_FOR_maskcmpv2df3, "__builtin_ia32_cmpgepd", IX86_BUILTIN_CMPGEPD, LE, 1 }, + { MASK_SSE2, CODE_FOR_maskcmpv2df3, "__builtin_ia32_cmpunordpd", IX86_BUILTIN_CMPUNORDPD, UNORDERED, 0 }, + { MASK_SSE2, CODE_FOR_maskncmpv2df3, "__builtin_ia32_cmpneqpd", IX86_BUILTIN_CMPNEQPD, EQ, 0 }, + { MASK_SSE2, CODE_FOR_maskncmpv2df3, "__builtin_ia32_cmpnltpd", IX86_BUILTIN_CMPNLTPD, LT, 0 }, + { MASK_SSE2, CODE_FOR_maskncmpv2df3, "__builtin_ia32_cmpnlepd", IX86_BUILTIN_CMPNLEPD, LE, 0 }, + { MASK_SSE2, CODE_FOR_maskncmpv2df3, "__builtin_ia32_cmpngtpd", IX86_BUILTIN_CMPNGTPD, LT, 1 }, + { MASK_SSE2, CODE_FOR_maskncmpv2df3, "__builtin_ia32_cmpngepd", IX86_BUILTIN_CMPNGEPD, LE, 1 }, + { MASK_SSE2, CODE_FOR_maskncmpv2df3, "__builtin_ia32_cmpordpd", IX86_BUILTIN_CMPORDPD, UNORDERED, 0 }, + { MASK_SSE2, CODE_FOR_vmmaskcmpv2df3, "__builtin_ia32_cmpeqsd", IX86_BUILTIN_CMPEQSD, EQ, 0 }, + { MASK_SSE2, CODE_FOR_vmmaskcmpv2df3, "__builtin_ia32_cmpltsd", IX86_BUILTIN_CMPLTSD, LT, 0 }, + { MASK_SSE2, CODE_FOR_vmmaskcmpv2df3, "__builtin_ia32_cmplesd", IX86_BUILTIN_CMPLESD, LE, 0 }, + { MASK_SSE2, CODE_FOR_vmmaskcmpv2df3, "__builtin_ia32_cmpunordsd", IX86_BUILTIN_CMPUNORDSD, UNORDERED, 0 }, + { MASK_SSE2, CODE_FOR_vmmaskncmpv2df3, "__builtin_ia32_cmpneqsd", IX86_BUILTIN_CMPNEQSD, EQ, 0 }, + { MASK_SSE2, CODE_FOR_vmmaskncmpv2df3, "__builtin_ia32_cmpnltsd", IX86_BUILTIN_CMPNLTSD, LT, 0 }, + { MASK_SSE2, CODE_FOR_vmmaskncmpv2df3, "__builtin_ia32_cmpnlesd", IX86_BUILTIN_CMPNLESD, LE, 0 }, + { MASK_SSE2, CODE_FOR_vmmaskncmpv2df3, "__builtin_ia32_cmpordsd", IX86_BUILTIN_CMPORDSD, UNORDERED, 0 }, { MASK_SSE2, CODE_FOR_sminv2df3, "__builtin_ia32_minpd", IX86_BUILTIN_MINPD, 0, 0 }, { MASK_SSE2, CODE_FOR_smaxv2df3, "__builtin_ia32_maxpd", IX86_BUILTIN_MAXPD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmsminv2df3, "__builtin_ia32_minsd", IX86_BUILTIN_MINSD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_vmsmaxv2df3, "__builtin_ia32_maxsd", IX86_BUILTIN_MAXSD, 0, 0 }, + { MASK_SSE2, CODE_FOR_vmsminv2df3, "__builtin_ia32_minsd", IX86_BUILTIN_MINSD, 0, 0 }, + { MASK_SSE2, CODE_FOR_vmsmaxv2df3, "__builtin_ia32_maxsd", IX86_BUILTIN_MAXSD, 0, 0 }, - { MASK_SSE2, CODE_FOR_andv2df3, "__builtin_ia32_andpd", IX86_BUILTIN_ANDPD, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_andv2df3, "__builtin_ia32_andpd", IX86_BUILTIN_ANDPD, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_nandv2df3, "__builtin_ia32_andnpd", IX86_BUILTIN_ANDNPD, 0, 0 }, - { MASK_SSE2, CODE_FOR_iorv2df3, "__builtin_ia32_orpd", IX86_BUILTIN_ORPD, 0, 0 }, - { MASK_SSE2, CODE_FOR_xorv2df3, "__builtin_ia32_xorpd", IX86_BUILTIN_XORPD, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_iorv2df3, "__builtin_ia32_orpd", IX86_BUILTIN_ORPD, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_xorv2df3, "__builtin_ia32_xorpd", IX86_BUILTIN_XORPD, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_movsd, "__builtin_ia32_movsd", IX86_BUILTIN_MOVSD, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_unpckhpd, "__builtin_ia32_unpckhpd", IX86_BUILTIN_UNPCKHPD, 0, 0 }, @@ -14824,32 +13068,34 @@ static const struct builtin_description bdesc_2arg[] = { MASK_SSE2, CODE_FOR_subv4si3, "__builtin_ia32_psubd128", IX86_BUILTIN_PSUBD128, 0, 0 }, { MASK_SSE2, CODE_FOR_subv2di3, "__builtin_ia32_psubq128", IX86_BUILTIN_PSUBQ128, 0, 0 }, - { MASK_MMX, CODE_FOR_sse2_ssaddv16qi3, "__builtin_ia32_paddsb128", IX86_BUILTIN_PADDSB128, 0, 0 }, - { MASK_MMX, CODE_FOR_sse2_ssaddv8hi3, "__builtin_ia32_paddsw128", IX86_BUILTIN_PADDSW128, 0, 0 }, - { MASK_MMX, CODE_FOR_sse2_sssubv16qi3, "__builtin_ia32_psubsb128", IX86_BUILTIN_PSUBSB128, 0, 0 }, - { MASK_MMX, CODE_FOR_sse2_sssubv8hi3, "__builtin_ia32_psubsw128", IX86_BUILTIN_PSUBSW128, 0, 0 }, - { MASK_MMX, CODE_FOR_sse2_usaddv16qi3, "__builtin_ia32_paddusb128", IX86_BUILTIN_PADDUSB128, 0, 0 }, - { MASK_MMX, CODE_FOR_sse2_usaddv8hi3, "__builtin_ia32_paddusw128", IX86_BUILTIN_PADDUSW128, 0, 0 }, - { MASK_MMX, CODE_FOR_sse2_ussubv16qi3, "__builtin_ia32_psubusb128", IX86_BUILTIN_PSUBUSB128, 0, 0 }, - { MASK_MMX, CODE_FOR_sse2_ussubv8hi3, "__builtin_ia32_psubusw128", IX86_BUILTIN_PSUBUSW128, 0, 0 }, + { MASK_MMX, CODE_FOR_ssaddv16qi3, "__builtin_ia32_paddsb128", IX86_BUILTIN_PADDSB128, 0, 0 }, + { MASK_MMX, CODE_FOR_ssaddv8hi3, "__builtin_ia32_paddsw128", IX86_BUILTIN_PADDSW128, 0, 0 }, + { MASK_MMX, CODE_FOR_sssubv16qi3, "__builtin_ia32_psubsb128", IX86_BUILTIN_PSUBSB128, 0, 0 }, + { MASK_MMX, CODE_FOR_sssubv8hi3, "__builtin_ia32_psubsw128", IX86_BUILTIN_PSUBSW128, 0, 0 }, + { MASK_MMX, CODE_FOR_usaddv16qi3, "__builtin_ia32_paddusb128", IX86_BUILTIN_PADDUSB128, 0, 0 }, + { MASK_MMX, CODE_FOR_usaddv8hi3, "__builtin_ia32_paddusw128", IX86_BUILTIN_PADDUSW128, 0, 0 }, + { MASK_MMX, CODE_FOR_ussubv16qi3, "__builtin_ia32_psubusb128", IX86_BUILTIN_PSUBUSB128, 0, 0 }, + { MASK_MMX, CODE_FOR_ussubv8hi3, "__builtin_ia32_psubusw128", IX86_BUILTIN_PSUBUSW128, 0, 0 }, { MASK_SSE2, CODE_FOR_mulv8hi3, "__builtin_ia32_pmullw128", IX86_BUILTIN_PMULLW128, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_smulv8hi3_highpart, "__builtin_ia32_pmulhw128", IX86_BUILTIN_PMULHW128, 0, 0 }, + { MASK_SSE2, CODE_FOR_smulv8hi3_highpart, "__builtin_ia32_pmulhw128", IX86_BUILTIN_PMULHW128, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_umulsidi3, "__builtin_ia32_pmuludq", IX86_BUILTIN_PMULUDQ, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_umulv2siv2di3, "__builtin_ia32_pmuludq128", IX86_BUILTIN_PMULUDQ128, 0, 0 }, - { MASK_SSE2, CODE_FOR_andv2di3, "__builtin_ia32_pand128", IX86_BUILTIN_PAND128, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_andv2di3, "__builtin_ia32_pand128", IX86_BUILTIN_PAND128, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_nandv2di3, "__builtin_ia32_pandn128", IX86_BUILTIN_PANDN128, 0, 0 }, - { MASK_SSE2, CODE_FOR_iorv2di3, "__builtin_ia32_por128", IX86_BUILTIN_POR128, 0, 0 }, - { MASK_SSE2, CODE_FOR_xorv2di3, "__builtin_ia32_pxor128", IX86_BUILTIN_PXOR128, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_iorv2di3, "__builtin_ia32_por128", IX86_BUILTIN_POR128, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_xorv2di3, "__builtin_ia32_pxor128", IX86_BUILTIN_PXOR128, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_uavgv16qi3, "__builtin_ia32_pavgb128", IX86_BUILTIN_PAVGB128, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_uavgv8hi3, "__builtin_ia32_pavgw128", IX86_BUILTIN_PAVGW128, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_eqv16qi3, "__builtin_ia32_pcmpeqb128", IX86_BUILTIN_PCMPEQB128, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_eqv8hi3, "__builtin_ia32_pcmpeqw128", IX86_BUILTIN_PCMPEQW128, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_eqv4si3, "__builtin_ia32_pcmpeqd128", IX86_BUILTIN_PCMPEQD128, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_gtv16qi3, "__builtin_ia32_pcmpgtb128", IX86_BUILTIN_PCMPGTB128, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_gtv8hi3, "__builtin_ia32_pcmpgtw128", IX86_BUILTIN_PCMPGTW128, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_gtv4si3, "__builtin_ia32_pcmpgtd128", IX86_BUILTIN_PCMPGTD128, 0, 0 }, + { MASK_SSE2, CODE_FOR_eqv16qi3, "__builtin_ia32_pcmpeqb128", IX86_BUILTIN_PCMPEQB128, 0, 0 }, + { MASK_SSE2, CODE_FOR_eqv8hi3, "__builtin_ia32_pcmpeqw128", IX86_BUILTIN_PCMPEQW128, 0, 0 }, + { MASK_SSE2, CODE_FOR_eqv4si3, "__builtin_ia32_pcmpeqd128", IX86_BUILTIN_PCMPEQD128, 0, 0 }, + { MASK_SSE2, CODE_FOR_gtv16qi3, "__builtin_ia32_pcmpgtb128", IX86_BUILTIN_PCMPGTB128, 0, 0 }, + { MASK_SSE2, CODE_FOR_gtv8hi3, "__builtin_ia32_pcmpgtw128", IX86_BUILTIN_PCMPGTW128, 0, 0 }, + { MASK_SSE2, CODE_FOR_gtv4si3, "__builtin_ia32_pcmpgtd128", IX86_BUILTIN_PCMPGTD128, 0, 0 }, { MASK_SSE2, CODE_FOR_umaxv16qi3, "__builtin_ia32_pmaxub128", IX86_BUILTIN_PMAXUB128, 0, 0 }, { MASK_SSE2, CODE_FOR_smaxv8hi3, "__builtin_ia32_pmaxsw128", IX86_BUILTIN_PMAXSW128, 0, 0 }, @@ -14869,37 +13115,42 @@ static const struct builtin_description bdesc_2arg[] = { MASK_SSE2, CODE_FOR_sse2_packssdw, "__builtin_ia32_packssdw128", IX86_BUILTIN_PACKSSDW128, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_packuswb, "__builtin_ia32_packuswb128", IX86_BUILTIN_PACKUSWB128, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_umulv8hi3_highpart, "__builtin_ia32_pmulhuw128", IX86_BUILTIN_PMULHUW128, 0, 0 }, + { MASK_SSE2, CODE_FOR_umulv8hi3_highpart, "__builtin_ia32_pmulhuw128", IX86_BUILTIN_PMULHUW128, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_psadbw, 0, IX86_BUILTIN_PSADBW128, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_umulsidi3, 0, IX86_BUILTIN_PMULUDQ, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_umulv2siv2di3, 0, IX86_BUILTIN_PMULUDQ128, 0, 0 }, - + { MASK_SSE2, CODE_FOR_ashlv8hi3_ti, 0, IX86_BUILTIN_PSLLW128, 0, 0 }, { MASK_SSE2, CODE_FOR_ashlv8hi3, 0, IX86_BUILTIN_PSLLWI128, 0, 0 }, + { MASK_SSE2, CODE_FOR_ashlv4si3_ti, 0, IX86_BUILTIN_PSLLD128, 0, 0 }, { MASK_SSE2, CODE_FOR_ashlv4si3, 0, IX86_BUILTIN_PSLLDI128, 0, 0 }, + { MASK_SSE2, CODE_FOR_ashlv2di3_ti, 0, IX86_BUILTIN_PSLLQ128, 0, 0 }, { MASK_SSE2, CODE_FOR_ashlv2di3, 0, IX86_BUILTIN_PSLLQI128, 0, 0 }, + { MASK_SSE2, CODE_FOR_lshrv8hi3_ti, 0, IX86_BUILTIN_PSRLW128, 0, 0 }, { MASK_SSE2, CODE_FOR_lshrv8hi3, 0, IX86_BUILTIN_PSRLWI128, 0, 0 }, + { MASK_SSE2, CODE_FOR_lshrv4si3_ti, 0, IX86_BUILTIN_PSRLD128, 0, 0 }, { MASK_SSE2, CODE_FOR_lshrv4si3, 0, IX86_BUILTIN_PSRLDI128, 0, 0 }, + { MASK_SSE2, CODE_FOR_lshrv2di3_ti, 0, IX86_BUILTIN_PSRLQ128, 0, 0 }, { MASK_SSE2, CODE_FOR_lshrv2di3, 0, IX86_BUILTIN_PSRLQI128, 0, 0 }, + { MASK_SSE2, CODE_FOR_ashrv8hi3_ti, 0, IX86_BUILTIN_PSRAW128, 0, 0 }, { MASK_SSE2, CODE_FOR_ashrv8hi3, 0, IX86_BUILTIN_PSRAWI128, 0, 0 }, + { MASK_SSE2, CODE_FOR_ashrv4si3_ti, 0, IX86_BUILTIN_PSRAD128, 0, 0 }, { MASK_SSE2, CODE_FOR_ashrv4si3, 0, IX86_BUILTIN_PSRADI128, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_pmaddwd, 0, IX86_BUILTIN_PMADDWD128, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtsi2sd, 0, IX86_BUILTIN_CVTSI2SD, 0, 0 }, - { MASK_SSE2 | MASK_64BIT, CODE_FOR_sse2_cvtsi2sdq, 0, IX86_BUILTIN_CVTSI642SD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtsd2ss, 0, IX86_BUILTIN_CVTSD2SS, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtss2sd, 0, IX86_BUILTIN_CVTSS2SD, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtsi2sd, 0, IX86_BUILTIN_CVTSI2SD, 0, 0 }, + { MASK_SSE2 | MASK_64BIT, CODE_FOR_cvtsi2sdq, 0, IX86_BUILTIN_CVTSI642SD, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtsd2ss, 0, IX86_BUILTIN_CVTSD2SS, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtss2sd, 0, IX86_BUILTIN_CVTSS2SD, 0, 0 }, /* SSE3 MMX */ - { MASK_SSE3, CODE_FOR_sse3_addsubv4sf3, "__builtin_ia32_addsubps", IX86_BUILTIN_ADDSUBPS, 0, 0 }, - { MASK_SSE3, CODE_FOR_sse3_addsubv2df3, "__builtin_ia32_addsubpd", IX86_BUILTIN_ADDSUBPD, 0, 0 }, - { MASK_SSE3, CODE_FOR_sse3_haddv4sf3, "__builtin_ia32_haddps", IX86_BUILTIN_HADDPS, 0, 0 }, - { MASK_SSE3, CODE_FOR_sse3_haddv2df3, "__builtin_ia32_haddpd", IX86_BUILTIN_HADDPD, 0, 0 }, - { MASK_SSE3, CODE_FOR_sse3_hsubv4sf3, "__builtin_ia32_hsubps", IX86_BUILTIN_HSUBPS, 0, 0 }, - { MASK_SSE3, CODE_FOR_sse3_hsubv2df3, "__builtin_ia32_hsubpd", IX86_BUILTIN_HSUBPD, 0, 0 } + { MASK_SSE3, CODE_FOR_addsubv4sf3, "__builtin_ia32_addsubps", IX86_BUILTIN_ADDSUBPS, 0, 0 }, + { MASK_SSE3, CODE_FOR_addsubv2df3, "__builtin_ia32_addsubpd", IX86_BUILTIN_ADDSUBPD, 0, 0 }, + { MASK_SSE3, CODE_FOR_haddv4sf3, "__builtin_ia32_haddps", IX86_BUILTIN_HADDPS, 0, 0 }, + { MASK_SSE3, CODE_FOR_haddv2df3, "__builtin_ia32_haddpd", IX86_BUILTIN_HADDPD, 0, 0 }, + { MASK_SSE3, CODE_FOR_hsubv4sf3, "__builtin_ia32_hsubps", IX86_BUILTIN_HSUBPS, 0, 0 }, + { MASK_SSE3, CODE_FOR_hsubv2df3, "__builtin_ia32_hsubpd", IX86_BUILTIN_HSUBPD, 0, 0 } }; static const struct builtin_description bdesc_1arg[] = @@ -14908,47 +13159,52 @@ static const struct builtin_description bdesc_1arg[] = { MASK_SSE, CODE_FOR_sse_movmskps, 0, IX86_BUILTIN_MOVMSKPS, 0, 0 }, { MASK_SSE, CODE_FOR_sqrtv4sf2, 0, IX86_BUILTIN_SQRTPS, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_rsqrtv4sf2, 0, IX86_BUILTIN_RSQRTPS, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_rcpv4sf2, 0, IX86_BUILTIN_RCPPS, 0, 0 }, + { MASK_SSE, CODE_FOR_rsqrtv4sf2, 0, IX86_BUILTIN_RSQRTPS, 0, 0 }, + { MASK_SSE, CODE_FOR_rcpv4sf2, 0, IX86_BUILTIN_RCPPS, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_cvtps2pi, 0, IX86_BUILTIN_CVTPS2PI, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_cvtss2si, 0, IX86_BUILTIN_CVTSS2SI, 0, 0 }, - { MASK_SSE | MASK_64BIT, CODE_FOR_sse_cvtss2siq, 0, IX86_BUILTIN_CVTSS2SI64, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_cvttps2pi, 0, IX86_BUILTIN_CVTTPS2PI, 0, 0 }, - { MASK_SSE, CODE_FOR_sse_cvttss2si, 0, IX86_BUILTIN_CVTTSS2SI, 0, 0 }, - { MASK_SSE | MASK_64BIT, CODE_FOR_sse_cvttss2siq, 0, IX86_BUILTIN_CVTTSS2SI64, 0, 0 }, + { MASK_SSE, CODE_FOR_cvtps2pi, 0, IX86_BUILTIN_CVTPS2PI, 0, 0 }, + { MASK_SSE, CODE_FOR_cvtss2si, 0, IX86_BUILTIN_CVTSS2SI, 0, 0 }, + { MASK_SSE | MASK_64BIT, CODE_FOR_cvtss2siq, 0, IX86_BUILTIN_CVTSS2SI64, 0, 0 }, + { MASK_SSE, CODE_FOR_cvttps2pi, 0, IX86_BUILTIN_CVTTPS2PI, 0, 0 }, + { MASK_SSE, CODE_FOR_cvttss2si, 0, IX86_BUILTIN_CVTTSS2SI, 0, 0 }, + { MASK_SSE | MASK_64BIT, CODE_FOR_cvttss2siq, 0, IX86_BUILTIN_CVTTSS2SI64, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_pmovmskb, 0, IX86_BUILTIN_PMOVMSKB128, 0, 0 }, { MASK_SSE2, CODE_FOR_sse2_movmskpd, 0, IX86_BUILTIN_MOVMSKPD, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_movq2dq, 0, IX86_BUILTIN_MOVQ2DQ, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_movdq2q, 0, IX86_BUILTIN_MOVDQ2Q, 0, 0 }, { MASK_SSE2, CODE_FOR_sqrtv2df2, 0, IX86_BUILTIN_SQRTPD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtdq2pd, 0, IX86_BUILTIN_CVTDQ2PD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtdq2ps, 0, IX86_BUILTIN_CVTDQ2PS, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtdq2pd, 0, IX86_BUILTIN_CVTDQ2PD, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtdq2ps, 0, IX86_BUILTIN_CVTDQ2PS, 0, 0 }, + + { MASK_SSE2, CODE_FOR_cvtpd2dq, 0, IX86_BUILTIN_CVTPD2DQ, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtpd2pi, 0, IX86_BUILTIN_CVTPD2PI, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtpd2ps, 0, IX86_BUILTIN_CVTPD2PS, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvttpd2dq, 0, IX86_BUILTIN_CVTTPD2DQ, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvttpd2pi, 0, IX86_BUILTIN_CVTTPD2PI, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtpd2dq, 0, IX86_BUILTIN_CVTPD2DQ, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtpd2pi, 0, IX86_BUILTIN_CVTPD2PI, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtpd2ps, 0, IX86_BUILTIN_CVTPD2PS, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvttpd2dq, 0, IX86_BUILTIN_CVTTPD2DQ, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvttpd2pi, 0, IX86_BUILTIN_CVTTPD2PI, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtpi2pd, 0, IX86_BUILTIN_CVTPI2PD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtpi2pd, 0, IX86_BUILTIN_CVTPI2PD, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtsd2si, 0, IX86_BUILTIN_CVTSD2SI, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvttsd2si, 0, IX86_BUILTIN_CVTTSD2SI, 0, 0 }, + { MASK_SSE2 | MASK_64BIT, CODE_FOR_cvtsd2siq, 0, IX86_BUILTIN_CVTSD2SI64, 0, 0 }, + { MASK_SSE2 | MASK_64BIT, CODE_FOR_cvttsd2siq, 0, IX86_BUILTIN_CVTTSD2SI64, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtsd2si, 0, IX86_BUILTIN_CVTSD2SI, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvttsd2si, 0, IX86_BUILTIN_CVTTSD2SI, 0, 0 }, - { MASK_SSE2 | MASK_64BIT, CODE_FOR_sse2_cvtsd2siq, 0, IX86_BUILTIN_CVTSD2SI64, 0, 0 }, - { MASK_SSE2 | MASK_64BIT, CODE_FOR_sse2_cvttsd2siq, 0, IX86_BUILTIN_CVTTSD2SI64, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtps2dq, 0, IX86_BUILTIN_CVTPS2DQ, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvtps2pd, 0, IX86_BUILTIN_CVTPS2PD, 0, 0 }, + { MASK_SSE2, CODE_FOR_cvttps2dq, 0, IX86_BUILTIN_CVTTPS2DQ, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtps2dq, 0, IX86_BUILTIN_CVTPS2DQ, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvtps2pd, 0, IX86_BUILTIN_CVTPS2PD, 0, 0 }, - { MASK_SSE2, CODE_FOR_sse2_cvttps2dq, 0, IX86_BUILTIN_CVTTPS2DQ, 0, 0 }, + { MASK_SSE2, CODE_FOR_sse2_movq, 0, IX86_BUILTIN_MOVQ, 0, 0 }, /* SSE3 */ - { MASK_SSE3, CODE_FOR_sse3_movshdup, 0, IX86_BUILTIN_MOVSHDUP, 0, 0 }, - { MASK_SSE3, CODE_FOR_sse3_movsldup, 0, IX86_BUILTIN_MOVSLDUP, 0, 0 }, + { MASK_SSE3, CODE_FOR_movshdup, 0, IX86_BUILTIN_MOVSHDUP, 0, 0 }, + { MASK_SSE3, CODE_FOR_movsldup, 0, IX86_BUILTIN_MOVSLDUP, 0, 0 }, + { MASK_SSE3, CODE_FOR_movddup, 0, IX86_BUILTIN_MOVDDUP, 0, 0 } }; -static void +void ix86_init_builtins (void) { if (TARGET_MMX) @@ -14964,18 +13220,6 @@ ix86_init_mmx_sse_builtins (void) const struct builtin_description * d; size_t i; - tree V16QI_type_node = build_vector_type_for_mode (intQI_type_node, V16QImode); - tree V2SI_type_node = build_vector_type_for_mode (intSI_type_node, V2SImode); - tree V2SF_type_node = build_vector_type_for_mode (float_type_node, V2SFmode); - tree V2DI_type_node - = build_vector_type_for_mode (long_long_integer_type_node, V2DImode); - tree V2DF_type_node = build_vector_type_for_mode (double_type_node, V2DFmode); - tree V4SF_type_node = build_vector_type_for_mode (float_type_node, V4SFmode); - tree V4SI_type_node = build_vector_type_for_mode (intSI_type_node, V4SImode); - tree V4HI_type_node = build_vector_type_for_mode (intHI_type_node, V4HImode); - tree V8QI_type_node = build_vector_type_for_mode (intQI_type_node, V8QImode); - tree V8HI_type_node = build_vector_type_for_mode (intHI_type_node, V8HImode); - tree pchar_type_node = build_pointer_type (char_type_node); tree pcchar_type_node = build_pointer_type ( build_type_variant (char_type_node, 1, 0)); @@ -15012,7 +13256,13 @@ ix86_init_mmx_sse_builtins (void) tree v4sf_ftype_v4sf_v2si = build_function_type_list (V4SF_type_node, V4SF_type_node, V2SI_type_node, NULL_TREE); - + tree int_ftype_v4hi_int + = build_function_type_list (integer_type_node, + V4HI_type_node, integer_type_node, NULL_TREE); + tree v4hi_ftype_v4hi_int_int + = build_function_type_list (V4HI_type_node, V4HI_type_node, + integer_type_node, integer_type_node, + NULL_TREE); /* Miscellaneous. */ tree v8qi_ftype_v4hi_v4hi = build_function_type_list (V8QI_type_node, @@ -15051,6 +13301,10 @@ ix86_init_mmx_sse_builtins (void) NULL_TREE); tree unsigned_ftype_void = build_function_type (unsigned_type_node, void_list_node); + tree di_ftype_void + = build_function_type (long_long_unsigned_type_node, void_list_node); + tree v4sf_ftype_void + = build_function_type (V4SF_type_node, void_list_node); tree v2si_ftype_v4sf = build_function_type_list (V2SI_type_node, V4SF_type_node, NULL_TREE); /* Loads/stores. */ @@ -15114,6 +13368,8 @@ ix86_init_mmx_sse_builtins (void) = build_function_type_list (V2SI_type_node, V2SF_type_node, V2SF_type_node, NULL_TREE); tree pint_type_node = build_pointer_type (integer_type_node); + tree pcint_type_node = build_pointer_type ( + build_type_variant (integer_type_node, 1, 0)); tree pdouble_type_node = build_pointer_type (double_type_node); tree pcdouble_type_node = build_pointer_type ( build_type_variant (double_type_node, 1, 0)); @@ -15121,8 +13377,21 @@ ix86_init_mmx_sse_builtins (void) = build_function_type_list (integer_type_node, V2DF_type_node, V2DF_type_node, NULL_TREE); + tree ti_ftype_void + = build_function_type (intTI_type_node, void_list_node); + tree v2di_ftype_void + = build_function_type (V2DI_type_node, void_list_node); + tree ti_ftype_ti_ti + = build_function_type_list (intTI_type_node, + intTI_type_node, intTI_type_node, NULL_TREE); tree void_ftype_pcvoid = build_function_type_list (void_type_node, const_ptr_type_node, NULL_TREE); + tree v2di_ftype_di + = build_function_type_list (V2DI_type_node, + long_long_unsigned_type_node, NULL_TREE); + tree di_ftype_v2di + = build_function_type_list (long_long_unsigned_type_node, + V2DI_type_node, NULL_TREE); tree v4sf_ftype_v4si = build_function_type_list (V4SF_type_node, V4SI_type_node, NULL_TREE); tree v4si_ftype_v4sf @@ -15162,9 +13431,12 @@ ix86_init_mmx_sse_builtins (void) V2DF_type_node, V2DF_type_node, integer_type_node, NULL_TREE); - tree v2df_ftype_v2df_pcdouble + tree v2df_ftype_v2df_pv2si = build_function_type_list (V2DF_type_node, - V2DF_type_node, pcdouble_type_node, NULL_TREE); + V2DF_type_node, pv2si_type_node, NULL_TREE); + tree void_ftype_pv2si_v2df + = build_function_type_list (void_type_node, + pv2si_type_node, V2DF_type_node, NULL_TREE); tree void_ftype_pdouble_v2df = build_function_type_list (void_type_node, pdouble_type_node, V2DF_type_node, NULL_TREE); @@ -15197,6 +13469,18 @@ ix86_init_mmx_sse_builtins (void) V2DF_type_node, V2DF_type_node, NULL_TREE); tree v2df_ftype_v2df = build_function_type_list (V2DF_type_node, V2DF_type_node, NULL_TREE); + tree v2df_ftype_double + = build_function_type_list (V2DF_type_node, double_type_node, NULL_TREE); + tree v2df_ftype_double_double + = build_function_type_list (V2DF_type_node, + double_type_node, double_type_node, NULL_TREE); + tree int_ftype_v8hi_int + = build_function_type_list (integer_type_node, + V8HI_type_node, integer_type_node, NULL_TREE); + tree v8hi_ftype_v8hi_int_int + = build_function_type_list (V8HI_type_node, + V8HI_type_node, integer_type_node, + integer_type_node, NULL_TREE); tree v2di_ftype_v2di_int = build_function_type_list (V2DI_type_node, V2DI_type_node, integer_type_node, NULL_TREE); @@ -15206,21 +13490,21 @@ ix86_init_mmx_sse_builtins (void) tree v8hi_ftype_v8hi_int = build_function_type_list (V8HI_type_node, V8HI_type_node, integer_type_node, NULL_TREE); + tree v8hi_ftype_v8hi_v2di + = build_function_type_list (V8HI_type_node, + V8HI_type_node, V2DI_type_node, NULL_TREE); + tree v4si_ftype_v4si_v2di + = build_function_type_list (V4SI_type_node, + V4SI_type_node, V2DI_type_node, NULL_TREE); tree v4si_ftype_v8hi_v8hi = build_function_type_list (V4SI_type_node, V8HI_type_node, V8HI_type_node, NULL_TREE); tree di_ftype_v8qi_v8qi = build_function_type_list (long_long_unsigned_type_node, V8QI_type_node, V8QI_type_node, NULL_TREE); - tree di_ftype_v2si_v2si - = build_function_type_list (long_long_unsigned_type_node, - V2SI_type_node, V2SI_type_node, NULL_TREE); tree v2di_ftype_v16qi_v16qi = build_function_type_list (V2DI_type_node, V16QI_type_node, V16QI_type_node, NULL_TREE); - tree v2di_ftype_v4si_v4si - = build_function_type_list (V2DI_type_node, - V4SI_type_node, V4SI_type_node, NULL_TREE); tree int_ftype_v16qi = build_function_type_list (integer_type_node, V16QI_type_node, NULL_TREE); tree v16qi_ftype_pcchar @@ -15228,10 +13512,16 @@ ix86_init_mmx_sse_builtins (void) tree void_ftype_pchar_v16qi = build_function_type_list (void_type_node, pchar_type_node, V16QI_type_node, NULL_TREE); + tree v4si_ftype_pcint + = build_function_type_list (V4SI_type_node, pcint_type_node, NULL_TREE); + tree void_ftype_pcint_v4si + = build_function_type_list (void_type_node, + pcint_type_node, V4SI_type_node, NULL_TREE); + tree v2di_ftype_v2di + = build_function_type_list (V2DI_type_node, V2DI_type_node, NULL_TREE); tree float80_type; tree float128_type; - tree ftype; /* The __float80 type. */ if (TYPE_MODE (long_double_type_node) == XFmode) @@ -15241,18 +13531,15 @@ ix86_init_mmx_sse_builtins (void) { /* The __float80 type. */ float80_type = make_node (REAL_TYPE); - TYPE_PRECISION (float80_type) = 80; + TYPE_PRECISION (float80_type) = 96; layout_type (float80_type); (*lang_hooks.types.register_builtin_type) (float80_type, "__float80"); } - if (TARGET_64BIT) - { - float128_type = make_node (REAL_TYPE); - TYPE_PRECISION (float128_type) = 128; - layout_type (float128_type); - (*lang_hooks.types.register_builtin_type) (float128_type, "__float128"); - } + float128_type = make_node (REAL_TYPE); + TYPE_PRECISION (float128_type) = 128; + layout_type (float128_type); + (*lang_hooks.types.register_builtin_type) (float128_type, "__float128"); /* Add all builtins that are more or less simple operations on two operands. */ @@ -15284,6 +13571,9 @@ ix86_init_mmx_sse_builtins (void) case V2DFmode: type = v2df_ftype_v2df_v2df; break; + case TImode: + type = ti_ftype_ti_ti; + break; case V4SFmode: type = v4sf_ftype_v4sf_v4sf; break; @@ -15301,22 +13591,27 @@ ix86_init_mmx_sse_builtins (void) break; default: - gcc_unreachable (); + abort (); } /* Override for comparisons. */ - if (d->icode == CODE_FOR_sse_maskcmpv4sf3 - || d->icode == CODE_FOR_sse_vmmaskcmpv4sf3) + if (d->icode == CODE_FOR_maskcmpv4sf3 + || d->icode == CODE_FOR_maskncmpv4sf3 + || d->icode == CODE_FOR_vmmaskcmpv4sf3 + || d->icode == CODE_FOR_vmmaskncmpv4sf3) type = v4si_ftype_v4sf_v4sf; - if (d->icode == CODE_FOR_sse2_maskcmpv2df3 - || d->icode == CODE_FOR_sse2_vmmaskcmpv2df3) + if (d->icode == CODE_FOR_maskcmpv2df3 + || d->icode == CODE_FOR_maskncmpv2df3 + || d->icode == CODE_FOR_vmmaskcmpv2df3 + || d->icode == CODE_FOR_vmmaskncmpv2df3) type = v2di_ftype_v2df_v2df; def_builtin (d->mask, d->name, type, d->code); } /* Add the remaining MMX insns with somewhat more complicated types. */ + def_builtin (MASK_MMX, "__builtin_ia32_mmx_zero", di_ftype_void, IX86_BUILTIN_MMX_ZERO); def_builtin (MASK_MMX, "__builtin_ia32_emms", void_ftype_void, IX86_BUILTIN_EMMS); def_builtin (MASK_MMX, "__builtin_ia32_psllw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSLLW); def_builtin (MASK_MMX, "__builtin_ia32_pslld", v2si_ftype_v2si_di, IX86_BUILTIN_PSLLD); @@ -15329,7 +13624,7 @@ ix86_init_mmx_sse_builtins (void) def_builtin (MASK_MMX, "__builtin_ia32_psraw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSRAW); def_builtin (MASK_MMX, "__builtin_ia32_psrad", v2si_ftype_v2si_di, IX86_BUILTIN_PSRAD); - def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pshufw", v4hi_ftype_v4hi_int, IX86_BUILTIN_PSHUFW); + def_builtin (MASK_MMX, "__builtin_ia32_pshufw", v4hi_ftype_v4hi_int, IX86_BUILTIN_PSHUFW); def_builtin (MASK_MMX, "__builtin_ia32_pmaddwd", v2si_ftype_v4hi_v4hi, IX86_BUILTIN_PMADDWD); /* comi/ucomi insns. */ @@ -15355,10 +13650,17 @@ ix86_init_mmx_sse_builtins (void) def_builtin (MASK_SSE, "__builtin_ia32_cvttss2si", int_ftype_v4sf, IX86_BUILTIN_CVTTSS2SI); def_builtin (MASK_SSE | MASK_64BIT, "__builtin_ia32_cvttss2si64", int64_ftype_v4sf, IX86_BUILTIN_CVTTSS2SI64); + def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pextrw", int_ftype_v4hi_int, IX86_BUILTIN_PEXTRW); + def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pinsrw", v4hi_ftype_v4hi_int_int, IX86_BUILTIN_PINSRW); + def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_maskmovq", void_ftype_v8qi_v8qi_pchar, IX86_BUILTIN_MASKMOVQ); + def_builtin (MASK_SSE, "__builtin_ia32_loadaps", v4sf_ftype_pcfloat, IX86_BUILTIN_LOADAPS); def_builtin (MASK_SSE, "__builtin_ia32_loadups", v4sf_ftype_pcfloat, IX86_BUILTIN_LOADUPS); + def_builtin (MASK_SSE, "__builtin_ia32_loadss", v4sf_ftype_pcfloat, IX86_BUILTIN_LOADSS); + def_builtin (MASK_SSE, "__builtin_ia32_storeaps", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREAPS); def_builtin (MASK_SSE, "__builtin_ia32_storeups", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREUPS); + def_builtin (MASK_SSE, "__builtin_ia32_storess", void_ftype_pfloat_v4sf, IX86_BUILTIN_STORESS); def_builtin (MASK_SSE, "__builtin_ia32_loadhps", v4sf_ftype_v4sf_pv2si, IX86_BUILTIN_LOADHPS); def_builtin (MASK_SSE, "__builtin_ia32_loadlps", v4sf_ftype_v4sf_pv2si, IX86_BUILTIN_LOADLPS); @@ -15413,14 +13715,27 @@ ix86_init_mmx_sse_builtins (void) def_builtin (MASK_3DNOW_A, "__builtin_ia32_pswapdsf", v2sf_ftype_v2sf, IX86_BUILTIN_PSWAPDSF); def_builtin (MASK_3DNOW_A, "__builtin_ia32_pswapdsi", v2si_ftype_v2si, IX86_BUILTIN_PSWAPDSI); + def_builtin (MASK_SSE, "__builtin_ia32_setzerops", v4sf_ftype_void, IX86_BUILTIN_SSE_ZERO); + /* SSE2 */ + def_builtin (MASK_SSE2, "__builtin_ia32_pextrw128", int_ftype_v8hi_int, IX86_BUILTIN_PEXTRW128); + def_builtin (MASK_SSE2, "__builtin_ia32_pinsrw128", v8hi_ftype_v8hi_int_int, IX86_BUILTIN_PINSRW128); + def_builtin (MASK_SSE2, "__builtin_ia32_maskmovdqu", void_ftype_v16qi_v16qi_pchar, IX86_BUILTIN_MASKMOVDQU); + def_builtin (MASK_SSE2, "__builtin_ia32_movq2dq", v2di_ftype_di, IX86_BUILTIN_MOVQ2DQ); + def_builtin (MASK_SSE2, "__builtin_ia32_movdq2q", di_ftype_v2di, IX86_BUILTIN_MOVDQ2Q); + def_builtin (MASK_SSE2, "__builtin_ia32_loadapd", v2df_ftype_pcdouble, IX86_BUILTIN_LOADAPD); def_builtin (MASK_SSE2, "__builtin_ia32_loadupd", v2df_ftype_pcdouble, IX86_BUILTIN_LOADUPD); + def_builtin (MASK_SSE2, "__builtin_ia32_loadsd", v2df_ftype_pcdouble, IX86_BUILTIN_LOADSD); + def_builtin (MASK_SSE2, "__builtin_ia32_storeapd", void_ftype_pdouble_v2df, IX86_BUILTIN_STOREAPD); def_builtin (MASK_SSE2, "__builtin_ia32_storeupd", void_ftype_pdouble_v2df, IX86_BUILTIN_STOREUPD); + def_builtin (MASK_SSE2, "__builtin_ia32_storesd", void_ftype_pdouble_v2df, IX86_BUILTIN_STORESD); - def_builtin (MASK_SSE2, "__builtin_ia32_loadhpd", v2df_ftype_v2df_pcdouble, IX86_BUILTIN_LOADHPD); - def_builtin (MASK_SSE2, "__builtin_ia32_loadlpd", v2df_ftype_v2df_pcdouble, IX86_BUILTIN_LOADLPD); + def_builtin (MASK_SSE2, "__builtin_ia32_loadhpd", v2df_ftype_v2df_pv2si, IX86_BUILTIN_LOADHPD); + def_builtin (MASK_SSE2, "__builtin_ia32_loadlpd", v2df_ftype_v2df_pv2si, IX86_BUILTIN_LOADLPD); + def_builtin (MASK_SSE2, "__builtin_ia32_storehpd", void_ftype_pv2si_v2df, IX86_BUILTIN_STOREHPD); + def_builtin (MASK_SSE2, "__builtin_ia32_storelpd", void_ftype_pv2si_v2df, IX86_BUILTIN_STORELPD); def_builtin (MASK_SSE2, "__builtin_ia32_movmskpd", int_ftype_v2df, IX86_BUILTIN_MOVMSKPD); def_builtin (MASK_SSE2, "__builtin_ia32_pmovmskb128", int_ftype_v16qi, IX86_BUILTIN_PMOVMSKB128); @@ -15463,26 +13778,38 @@ ix86_init_mmx_sse_builtins (void) def_builtin (MASK_SSE2, "__builtin_ia32_cvtsd2ss", v4sf_ftype_v4sf_v2df, IX86_BUILTIN_CVTSD2SS); def_builtin (MASK_SSE2, "__builtin_ia32_cvtss2sd", v2df_ftype_v2df_v4sf, IX86_BUILTIN_CVTSS2SD); + def_builtin (MASK_SSE2, "__builtin_ia32_setpd1", v2df_ftype_double, IX86_BUILTIN_SETPD1); + def_builtin (MASK_SSE2, "__builtin_ia32_setpd", v2df_ftype_double_double, IX86_BUILTIN_SETPD); + def_builtin (MASK_SSE2, "__builtin_ia32_setzeropd", ti_ftype_void, IX86_BUILTIN_CLRPD); + def_builtin (MASK_SSE2, "__builtin_ia32_loadpd1", v2df_ftype_pcdouble, IX86_BUILTIN_LOADPD1); + def_builtin (MASK_SSE2, "__builtin_ia32_loadrpd", v2df_ftype_pcdouble, IX86_BUILTIN_LOADRPD); + def_builtin (MASK_SSE2, "__builtin_ia32_storepd1", void_ftype_pdouble_v2df, IX86_BUILTIN_STOREPD1); + def_builtin (MASK_SSE2, "__builtin_ia32_storerpd", void_ftype_pdouble_v2df, IX86_BUILTIN_STORERPD); + def_builtin (MASK_SSE2, "__builtin_ia32_clflush", void_ftype_pcvoid, IX86_BUILTIN_CLFLUSH); def_builtin (MASK_SSE2, "__builtin_ia32_lfence", void_ftype_void, IX86_BUILTIN_LFENCE); def_builtin (MASK_SSE2, "__builtin_ia32_mfence", void_ftype_void, IX86_BUILTIN_MFENCE); + def_builtin (MASK_SSE2, "__builtin_ia32_loaddqa", v16qi_ftype_pcchar, IX86_BUILTIN_LOADDQA); def_builtin (MASK_SSE2, "__builtin_ia32_loaddqu", v16qi_ftype_pcchar, IX86_BUILTIN_LOADDQU); + def_builtin (MASK_SSE2, "__builtin_ia32_loadd", v4si_ftype_pcint, IX86_BUILTIN_LOADD); + def_builtin (MASK_SSE2, "__builtin_ia32_storedqa", void_ftype_pchar_v16qi, IX86_BUILTIN_STOREDQA); def_builtin (MASK_SSE2, "__builtin_ia32_storedqu", void_ftype_pchar_v16qi, IX86_BUILTIN_STOREDQU); + def_builtin (MASK_SSE2, "__builtin_ia32_stored", void_ftype_pcint_v4si, IX86_BUILTIN_STORED); + def_builtin (MASK_SSE2, "__builtin_ia32_movq", v2di_ftype_v2di, IX86_BUILTIN_MOVQ); - def_builtin (MASK_SSE2, "__builtin_ia32_pmuludq", di_ftype_v2si_v2si, IX86_BUILTIN_PMULUDQ); - def_builtin (MASK_SSE2, "__builtin_ia32_pmuludq128", v2di_ftype_v4si_v4si, IX86_BUILTIN_PMULUDQ128); + def_builtin (MASK_SSE, "__builtin_ia32_setzero128", v2di_ftype_void, IX86_BUILTIN_CLRTI); - def_builtin (MASK_SSE2, "__builtin_ia32_psllw128", v8hi_ftype_v8hi_v8hi, IX86_BUILTIN_PSLLW128); - def_builtin (MASK_SSE2, "__builtin_ia32_pslld128", v4si_ftype_v4si_v4si, IX86_BUILTIN_PSLLD128); + def_builtin (MASK_SSE2, "__builtin_ia32_psllw128", v8hi_ftype_v8hi_v2di, IX86_BUILTIN_PSLLW128); + def_builtin (MASK_SSE2, "__builtin_ia32_pslld128", v4si_ftype_v4si_v2di, IX86_BUILTIN_PSLLD128); def_builtin (MASK_SSE2, "__builtin_ia32_psllq128", v2di_ftype_v2di_v2di, IX86_BUILTIN_PSLLQ128); - def_builtin (MASK_SSE2, "__builtin_ia32_psrlw128", v8hi_ftype_v8hi_v8hi, IX86_BUILTIN_PSRLW128); - def_builtin (MASK_SSE2, "__builtin_ia32_psrld128", v4si_ftype_v4si_v4si, IX86_BUILTIN_PSRLD128); + def_builtin (MASK_SSE2, "__builtin_ia32_psrlw128", v8hi_ftype_v8hi_v2di, IX86_BUILTIN_PSRLW128); + def_builtin (MASK_SSE2, "__builtin_ia32_psrld128", v4si_ftype_v4si_v2di, IX86_BUILTIN_PSRLD128); def_builtin (MASK_SSE2, "__builtin_ia32_psrlq128", v2di_ftype_v2di_v2di, IX86_BUILTIN_PSRLQ128); - def_builtin (MASK_SSE2, "__builtin_ia32_psraw128", v8hi_ftype_v8hi_v8hi, IX86_BUILTIN_PSRAW128); - def_builtin (MASK_SSE2, "__builtin_ia32_psrad128", v4si_ftype_v4si_v4si, IX86_BUILTIN_PSRAD128); + def_builtin (MASK_SSE2, "__builtin_ia32_psraw128", v8hi_ftype_v8hi_v2di, IX86_BUILTIN_PSRAW128); + def_builtin (MASK_SSE2, "__builtin_ia32_psrad128", v4si_ftype_v4si_v2di, IX86_BUILTIN_PSRAD128); def_builtin (MASK_SSE2, "__builtin_ia32_pslldqi128", v2di_ftype_v2di_int, IX86_BUILTIN_PSLLDQI128); def_builtin (MASK_SSE2, "__builtin_ia32_psllwi128", v8hi_ftype_v8hi_int, IX86_BUILTIN_PSLLWI128); @@ -15514,77 +13841,10 @@ ix86_init_mmx_sse_builtins (void) IX86_BUILTIN_MOVSLDUP); def_builtin (MASK_SSE3, "__builtin_ia32_lddqu", v16qi_ftype_pcchar, IX86_BUILTIN_LDDQU); - - /* Access to the vec_init patterns. */ - ftype = build_function_type_list (V2SI_type_node, integer_type_node, - integer_type_node, NULL_TREE); - def_builtin (MASK_MMX, "__builtin_ia32_vec_init_v2si", - ftype, IX86_BUILTIN_VEC_INIT_V2SI); - - ftype = build_function_type_list (V4HI_type_node, short_integer_type_node, - short_integer_type_node, - short_integer_type_node, - short_integer_type_node, NULL_TREE); - def_builtin (MASK_MMX, "__builtin_ia32_vec_init_v4hi", - ftype, IX86_BUILTIN_VEC_INIT_V4HI); - - ftype = build_function_type_list (V8QI_type_node, char_type_node, - char_type_node, char_type_node, - char_type_node, char_type_node, - char_type_node, char_type_node, - char_type_node, NULL_TREE); - def_builtin (MASK_MMX, "__builtin_ia32_vec_init_v8qi", - ftype, IX86_BUILTIN_VEC_INIT_V8QI); - - /* Access to the vec_extract patterns. */ - ftype = build_function_type_list (double_type_node, V2DF_type_node, - integer_type_node, NULL_TREE); - def_builtin (MASK_SSE, "__builtin_ia32_vec_ext_v2df", - ftype, IX86_BUILTIN_VEC_EXT_V2DF); - - ftype = build_function_type_list (long_long_integer_type_node, - V2DI_type_node, integer_type_node, - NULL_TREE); - def_builtin (MASK_SSE, "__builtin_ia32_vec_ext_v2di", - ftype, IX86_BUILTIN_VEC_EXT_V2DI); - - ftype = build_function_type_list (float_type_node, V4SF_type_node, - integer_type_node, NULL_TREE); - def_builtin (MASK_SSE, "__builtin_ia32_vec_ext_v4sf", - ftype, IX86_BUILTIN_VEC_EXT_V4SF); - - ftype = build_function_type_list (intSI_type_node, V4SI_type_node, - integer_type_node, NULL_TREE); - def_builtin (MASK_SSE, "__builtin_ia32_vec_ext_v4si", - ftype, IX86_BUILTIN_VEC_EXT_V4SI); - - ftype = build_function_type_list (intHI_type_node, V8HI_type_node, - integer_type_node, NULL_TREE); - def_builtin (MASK_SSE, "__builtin_ia32_vec_ext_v8hi", - ftype, IX86_BUILTIN_VEC_EXT_V8HI); - - ftype = build_function_type_list (intHI_type_node, V4HI_type_node, - integer_type_node, NULL_TREE); - def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_vec_ext_v4hi", - ftype, IX86_BUILTIN_VEC_EXT_V4HI); - - ftype = build_function_type_list (intSI_type_node, V2SI_type_node, - integer_type_node, NULL_TREE); - def_builtin (MASK_MMX, "__builtin_ia32_vec_ext_v2si", - ftype, IX86_BUILTIN_VEC_EXT_V2SI); - - /* Access to the vec_set patterns. */ - ftype = build_function_type_list (V8HI_type_node, V8HI_type_node, - intHI_type_node, - integer_type_node, NULL_TREE); - def_builtin (MASK_SSE, "__builtin_ia32_vec_set_v8hi", - ftype, IX86_BUILTIN_VEC_SET_V8HI); - - ftype = build_function_type_list (V4HI_type_node, V4HI_type_node, - intHI_type_node, - integer_type_node, NULL_TREE); - def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_vec_set_v4hi", - ftype, IX86_BUILTIN_VEC_SET_V4HI); + def_builtin (MASK_SSE3, "__builtin_ia32_loadddup", + v2df_ftype_pcdouble, IX86_BUILTIN_LOADDDUP); + def_builtin (MASK_SSE3, "__builtin_ia32_movddup", + v2df_ftype_v2df, IX86_BUILTIN_MOVDDUP); } /* Errors in the source file can cause expand_expr to return const0_rtx @@ -15593,8 +13853,17 @@ ix86_init_mmx_sse_builtins (void) static rtx safe_vector_operand (rtx x, enum machine_mode mode) { - if (x == const0_rtx) - x = CONST0_RTX (mode); + if (x != const0_rtx) + return x; + x = gen_reg_rtx (mode); + + if (VALID_MMX_REG_MODE (mode) || VALID_MMX_REG_MODE_3DNOW (mode)) + emit_insn (gen_mmx_clrdi (mode == DImode ? x + : gen_rtx_SUBREG (DImode, x, 0))); + else + emit_insn (gen_sse_clrv4sf (mode == V4SFmode ? x + : gen_rtx_SUBREG (V4SFmode, x, 0), + CONST0_RTX (V4SFmode))); return x; } @@ -15603,11 +13872,11 @@ safe_vector_operand (rtx x, enum machine_mode mode) static rtx ix86_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target) { - rtx pat, xops[3]; + rtx pat; tree arg0 = TREE_VALUE (arglist); tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); enum machine_mode tmode = insn_data[icode].operand[0].mode; enum machine_mode mode0 = insn_data[icode].operand[1].mode; enum machine_mode mode1 = insn_data[icode].operand[2].mode; @@ -15617,7 +13886,7 @@ ix86_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target) if (VECTOR_MODE_P (mode1)) op1 = safe_vector_operand (op1, mode1); - if (optimize || !target + if (! target || GET_MODE (target) != tmode || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) target = gen_reg_rtx (tmode); @@ -15629,35 +13898,22 @@ ix86_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target) op1 = gen_lowpart (TImode, x); } - /* The insn must want input operands in the same modes as the - result. */ - gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode) - && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode)); + /* In case the insn wants input operands in modes different from + the result, abort. */ + if ((GET_MODE (op0) != mode0 && GET_MODE (op0) != VOIDmode) + || (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode)) + abort (); - if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) op0 = copy_to_mode_reg (mode0, op0); - if (!(*insn_data[icode].operand[2].predicate) (op1, mode1)) + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) op1 = copy_to_mode_reg (mode1, op1); - /* ??? Using ix86_fixup_binary_operands is problematic when - we've got mismatched modes. Fake it. */ - - xops[0] = target; - xops[1] = op0; - xops[2] = op1; - - if (tmode == mode0 && tmode == mode1) - { - target = ix86_fixup_binary_operands (UNKNOWN, tmode, xops); - op0 = xops[1]; - op1 = xops[2]; - } - else if (optimize || !ix86_binary_operator_ok (UNKNOWN, tmode, xops)) - { - op0 = force_reg (mode0, op0); - op1 = force_reg (mode1, op1); - target = gen_reg_rtx (tmode); - } + /* In the commutative cases, both op0 and op1 are nonimmediate_operand, + yet one of the two must not be a memory. This is normally enforced + by expanders, but we didn't bother to create one here. */ + if (GET_CODE (op0) == MEM && GET_CODE (op1) == MEM) + op0 = copy_to_mode_reg (mode0, op0); pat = GEN_FCN (icode) (target, op0, op1); if (! pat) @@ -15674,8 +13930,8 @@ ix86_expand_store_builtin (enum insn_code icode, tree arglist) rtx pat; tree arg0 = TREE_VALUE (arglist); tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); enum machine_mode mode0 = insn_data[icode].operand[0].mode; enum machine_mode mode1 = insn_data[icode].operand[1].mode; @@ -15699,12 +13955,13 @@ ix86_expand_unop_builtin (enum insn_code icode, tree arglist, { rtx pat; tree arg0 = TREE_VALUE (arglist); - rtx op0 = expand_normal (arg0); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); enum machine_mode tmode = insn_data[icode].operand[0].mode; enum machine_mode mode0 = insn_data[icode].operand[1].mode; - if (optimize || !target + if (! target || GET_MODE (target) != tmode + || (do_load && GET_CODE (target) == MEM) || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) target = gen_reg_rtx (tmode); if (do_load) @@ -15714,8 +13971,7 @@ ix86_expand_unop_builtin (enum insn_code icode, tree arglist, if (VECTOR_MODE_P (mode0)) op0 = safe_vector_operand (op0, mode0); - if ((optimize && !register_operand (op0, mode0)) - || ! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) op0 = copy_to_mode_reg (mode0, op0); } @@ -15734,11 +13990,11 @@ ix86_expand_unop1_builtin (enum insn_code icode, tree arglist, rtx target) { rtx pat; tree arg0 = TREE_VALUE (arglist); - rtx op1, op0 = expand_normal (arg0); + rtx op1, op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); enum machine_mode tmode = insn_data[icode].operand[0].mode; enum machine_mode mode0 = insn_data[icode].operand[1].mode; - if (optimize || !target + if (! target || GET_MODE (target) != tmode || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) target = gen_reg_rtx (tmode); @@ -15746,8 +14002,7 @@ ix86_expand_unop1_builtin (enum insn_code icode, tree arglist, rtx target) if (VECTOR_MODE_P (mode0)) op0 = safe_vector_operand (op0, mode0); - if ((optimize && !register_operand (op0, mode0)) - || ! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) op0 = copy_to_mode_reg (mode0, op0); op1 = op0; @@ -15770,8 +14025,8 @@ ix86_expand_sse_compare (const struct builtin_description *d, tree arglist, rtx pat; tree arg0 = TREE_VALUE (arglist); tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); rtx op2; enum machine_mode tmode = insn_data[d->icode].operand[0].mode; enum machine_mode mode0 = insn_data[d->icode].operand[1].mode; @@ -15785,7 +14040,7 @@ ix86_expand_sse_compare (const struct builtin_description *d, tree arglist, /* Swap operands if we have a comparison that isn't available in hardware. */ - if (d->flag & BUILTIN_DESC_SWAP_OPERANDS) + if (d->flag) { rtx tmp = gen_reg_rtx (mode1); emit_move_insn (tmp, op1); @@ -15793,16 +14048,14 @@ ix86_expand_sse_compare (const struct builtin_description *d, tree arglist, op0 = tmp; } - if (optimize || !target + if (! target || GET_MODE (target) != tmode || ! (*insn_data[d->icode].operand[0].predicate) (target, tmode)) target = gen_reg_rtx (tmode); - if ((optimize && !register_operand (op0, mode0)) - || ! (*insn_data[d->icode].operand[1].predicate) (op0, mode0)) + if (! (*insn_data[d->icode].operand[1].predicate) (op0, mode0)) op0 = copy_to_mode_reg (mode0, op0); - if ((optimize && !register_operand (op1, mode1)) - || ! (*insn_data[d->icode].operand[2].predicate) (op1, mode1)) + if (! (*insn_data[d->icode].operand[2].predicate) (op1, mode1)) op1 = copy_to_mode_reg (mode1, op1); op2 = gen_rtx_fmt_ee (comparison, mode0, op0, op1); @@ -15822,8 +14075,8 @@ ix86_expand_sse_comi (const struct builtin_description *d, tree arglist, rtx pat; tree arg0 = TREE_VALUE (arglist); tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); rtx op2; enum machine_mode mode0 = insn_data[d->icode].operand[0].mode; enum machine_mode mode1 = insn_data[d->icode].operand[1].mode; @@ -15836,7 +14089,7 @@ ix86_expand_sse_comi (const struct builtin_description *d, tree arglist, /* Swap operands if we have a comparison that isn't available in hardware. */ - if (d->flag & BUILTIN_DESC_SWAP_OPERANDS) + if (d->flag) { rtx tmp = op1; op1 = op0; @@ -15847,11 +14100,9 @@ ix86_expand_sse_comi (const struct builtin_description *d, tree arglist, emit_move_insn (target, const0_rtx); target = gen_rtx_SUBREG (QImode, target, 0); - if ((optimize && !register_operand (op0, mode0)) - || !(*insn_data[d->icode].operand[0].predicate) (op0, mode0)) + if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0)) op0 = copy_to_mode_reg (mode0, op0); - if ((optimize && !register_operand (op1, mode1)) - || !(*insn_data[d->icode].operand[1].predicate) (op1, mode1)) + if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1)) op1 = copy_to_mode_reg (mode1, op1); op2 = gen_rtx_fmt_ee (comparison, mode0, op0, op1); @@ -15868,136 +14119,13 @@ ix86_expand_sse_comi (const struct builtin_description *d, tree arglist, return SUBREG_REG (target); } -/* Return the integer constant in ARG. Constrain it to be in the range - of the subparts of VEC_TYPE; issue an error if not. */ - -static int -get_element_number (tree vec_type, tree arg) -{ - unsigned HOST_WIDE_INT elt, max = TYPE_VECTOR_SUBPARTS (vec_type) - 1; - - if (!host_integerp (arg, 1) - || (elt = tree_low_cst (arg, 1), elt > max)) - { - error ("selector must be an integer constant in the range 0..%wi", max); - return 0; - } - - return elt; -} - -/* A subroutine of ix86_expand_builtin. These builtins are a wrapper around - ix86_expand_vector_init. We DO have language-level syntax for this, in - the form of (type){ init-list }. Except that since we can't place emms - instructions from inside the compiler, we can't allow the use of MMX - registers unless the user explicitly asks for it. So we do *not* define - vec_set/vec_extract/vec_init patterns for MMX modes in mmx.md. Instead - we have builtins invoked by mmintrin.h that gives us license to emit - these sorts of instructions. */ - -static rtx -ix86_expand_vec_init_builtin (tree type, tree arglist, rtx target) -{ - enum machine_mode tmode = TYPE_MODE (type); - enum machine_mode inner_mode = GET_MODE_INNER (tmode); - int i, n_elt = GET_MODE_NUNITS (tmode); - rtvec v = rtvec_alloc (n_elt); - - gcc_assert (VECTOR_MODE_P (tmode)); - - for (i = 0; i < n_elt; ++i, arglist = TREE_CHAIN (arglist)) - { - rtx x = expand_normal (TREE_VALUE (arglist)); - RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x); - } - - gcc_assert (arglist == NULL); - - if (!target || !register_operand (target, tmode)) - target = gen_reg_rtx (tmode); - - ix86_expand_vector_init (true, target, gen_rtx_PARALLEL (tmode, v)); - return target; -} - -/* A subroutine of ix86_expand_builtin. These builtins are a wrapper around - ix86_expand_vector_extract. They would be redundant (for non-MMX) if we - had a language-level syntax for referencing vector elements. */ - -static rtx -ix86_expand_vec_ext_builtin (tree arglist, rtx target) -{ - enum machine_mode tmode, mode0; - tree arg0, arg1; - int elt; - rtx op0; - - arg0 = TREE_VALUE (arglist); - arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - - op0 = expand_normal (arg0); - elt = get_element_number (TREE_TYPE (arg0), arg1); - - tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0))); - mode0 = TYPE_MODE (TREE_TYPE (arg0)); - gcc_assert (VECTOR_MODE_P (mode0)); - - op0 = force_reg (mode0, op0); - - if (optimize || !target || !register_operand (target, tmode)) - target = gen_reg_rtx (tmode); - - ix86_expand_vector_extract (true, target, op0, elt); - - return target; -} - -/* A subroutine of ix86_expand_builtin. These builtins are a wrapper around - ix86_expand_vector_set. They would be redundant (for non-MMX) if we had - a language-level syntax for referencing vector elements. */ - -static rtx -ix86_expand_vec_set_builtin (tree arglist) -{ - enum machine_mode tmode, mode1; - tree arg0, arg1, arg2; - int elt; - rtx op0, op1, target; - - arg0 = TREE_VALUE (arglist); - arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - - tmode = TYPE_MODE (TREE_TYPE (arg0)); - mode1 = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0))); - gcc_assert (VECTOR_MODE_P (tmode)); - - op0 = expand_expr (arg0, NULL_RTX, tmode, 0); - op1 = expand_expr (arg1, NULL_RTX, mode1, 0); - elt = get_element_number (TREE_TYPE (arg0), arg2); - - if (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode) - op1 = convert_modes (mode1, GET_MODE (op1), op1, true); - - op0 = force_reg (tmode, op0); - op1 = force_reg (mode1, op1); - - /* OP0 is the source of these builtin functions and shouldn't be - modified. Create a copy, use it and return it as target. */ - target = gen_reg_rtx (tmode); - emit_move_insn (target, op0); - ix86_expand_vector_set (true, target, op1, elt); - - return target; -} - /* Expand an expression EXP that calls a built-in function, with result going to TARGET if that's convenient (and in mode MODE if that's convenient). SUBTARGET may be used as the target for computing one of EXP's operands. IGNORE is nonzero if the value is to be ignored. */ -static rtx +rtx ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) @@ -16015,32 +14143,97 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, switch (fcode) { case IX86_BUILTIN_EMMS: - emit_insn (gen_mmx_emms ()); + emit_insn (gen_emms ()); return 0; case IX86_BUILTIN_SFENCE: - emit_insn (gen_sse_sfence ()); + emit_insn (gen_sfence ()); return 0; + case IX86_BUILTIN_PEXTRW: + case IX86_BUILTIN_PEXTRW128: + icode = (fcode == IX86_BUILTIN_PEXTRW + ? CODE_FOR_mmx_pextrw + : CODE_FOR_sse2_pextrw); + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + tmode = insn_data[icode].operand[0].mode; + mode0 = insn_data[icode].operand[1].mode; + mode1 = insn_data[icode].operand[2].mode; + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) + { + error ("selector must be an integer constant in the range 0..%i", + fcode == IX86_BUILTIN_PEXTRW ? 3:7); + return gen_reg_rtx (tmode); + } + if (target == 0 + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + pat = GEN_FCN (icode) (target, op0, op1); + if (! pat) + return 0; + emit_insn (pat); + return target; + + case IX86_BUILTIN_PINSRW: + case IX86_BUILTIN_PINSRW128: + icode = (fcode == IX86_BUILTIN_PINSRW + ? CODE_FOR_mmx_pinsrw + : CODE_FOR_sse2_pinsrw); + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); + tmode = insn_data[icode].operand[0].mode; + mode0 = insn_data[icode].operand[1].mode; + mode1 = insn_data[icode].operand[2].mode; + mode2 = insn_data[icode].operand[3].mode; + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + if (! (*insn_data[icode].operand[3].predicate) (op2, mode2)) + { + error ("selector must be an integer constant in the range 0..%i", + fcode == IX86_BUILTIN_PINSRW ? 15:255); + return const0_rtx; + } + if (target == 0 + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + pat = GEN_FCN (icode) (target, op0, op1, op2); + if (! pat) + return 0; + emit_insn (pat); + return target; + case IX86_BUILTIN_MASKMOVQ: case IX86_BUILTIN_MASKMOVDQU: icode = (fcode == IX86_BUILTIN_MASKMOVQ - ? CODE_FOR_mmx_maskmovq - : CODE_FOR_sse2_maskmovdqu); + ? (TARGET_64BIT ? CODE_FOR_mmx_maskmovq_rex : CODE_FOR_mmx_maskmovq) + : (TARGET_64BIT ? CODE_FOR_sse2_maskmovdqu_rex64 + : CODE_FOR_sse2_maskmovdqu)); /* Note the arg order is different from the operand order. */ arg1 = TREE_VALUE (arglist); arg2 = TREE_VALUE (TREE_CHAIN (arglist)); arg0 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - op0 = expand_normal (arg0); - op1 = expand_normal (arg1); - op2 = expand_normal (arg2); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); mode0 = insn_data[icode].operand[0].mode; mode1 = insn_data[icode].operand[1].mode; mode2 = insn_data[icode].operand[2].mode; - op0 = force_reg (Pmode, op0); - op0 = gen_rtx_MEM (mode1, op0); - if (! (*insn_data[icode].operand[0].predicate) (op0, mode0)) op0 = copy_to_mode_reg (mode0, op0); if (! (*insn_data[icode].operand[1].predicate) (op1, mode1)) @@ -16054,39 +14247,52 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, return 0; case IX86_BUILTIN_SQRTSS: - return ix86_expand_unop1_builtin (CODE_FOR_sse_vmsqrtv4sf2, arglist, target); + return ix86_expand_unop1_builtin (CODE_FOR_vmsqrtv4sf2, arglist, target); case IX86_BUILTIN_RSQRTSS: - return ix86_expand_unop1_builtin (CODE_FOR_sse_vmrsqrtv4sf2, arglist, target); + return ix86_expand_unop1_builtin (CODE_FOR_vmrsqrtv4sf2, arglist, target); case IX86_BUILTIN_RCPSS: - return ix86_expand_unop1_builtin (CODE_FOR_sse_vmrcpv4sf2, arglist, target); + return ix86_expand_unop1_builtin (CODE_FOR_vmrcpv4sf2, arglist, target); + + case IX86_BUILTIN_LOADAPS: + return ix86_expand_unop_builtin (CODE_FOR_sse_movaps, arglist, target, 1); case IX86_BUILTIN_LOADUPS: return ix86_expand_unop_builtin (CODE_FOR_sse_movups, arglist, target, 1); + case IX86_BUILTIN_STOREAPS: + return ix86_expand_store_builtin (CODE_FOR_sse_movaps, arglist); + case IX86_BUILTIN_STOREUPS: return ix86_expand_store_builtin (CODE_FOR_sse_movups, arglist); + case IX86_BUILTIN_LOADSS: + return ix86_expand_unop_builtin (CODE_FOR_sse_loadss, arglist, target, 1); + + case IX86_BUILTIN_STORESS: + return ix86_expand_store_builtin (CODE_FOR_sse_storess, arglist); + case IX86_BUILTIN_LOADHPS: case IX86_BUILTIN_LOADLPS: case IX86_BUILTIN_LOADHPD: case IX86_BUILTIN_LOADLPD: - icode = (fcode == IX86_BUILTIN_LOADHPS ? CODE_FOR_sse_loadhps - : fcode == IX86_BUILTIN_LOADLPS ? CODE_FOR_sse_loadlps - : fcode == IX86_BUILTIN_LOADHPD ? CODE_FOR_sse2_loadhpd - : CODE_FOR_sse2_loadlpd); + icode = (fcode == IX86_BUILTIN_LOADHPS ? CODE_FOR_sse_movhps + : fcode == IX86_BUILTIN_LOADLPS ? CODE_FOR_sse_movlps + : fcode == IX86_BUILTIN_LOADHPD ? CODE_FOR_sse2_movhpd + : CODE_FOR_sse2_movsd); arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - op0 = expand_normal (arg0); - op1 = expand_normal (arg1); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); tmode = insn_data[icode].operand[0].mode; mode0 = insn_data[icode].operand[1].mode; mode1 = insn_data[icode].operand[2].mode; - op0 = force_reg (mode0, op0); + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); op1 = gen_rtx_MEM (mode1, copy_to_mode_reg (Pmode, op1)); - if (optimize || target == 0 + if (target == 0 || GET_MODE (target) != tmode - || !register_operand (target, tmode)) + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) target = gen_reg_rtx (tmode); pat = GEN_FCN (icode) (target, op0, op1); if (! pat) @@ -16096,23 +14302,28 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, case IX86_BUILTIN_STOREHPS: case IX86_BUILTIN_STORELPS: - icode = (fcode == IX86_BUILTIN_STOREHPS ? CODE_FOR_sse_storehps - : CODE_FOR_sse_storelps); + case IX86_BUILTIN_STOREHPD: + case IX86_BUILTIN_STORELPD: + icode = (fcode == IX86_BUILTIN_STOREHPS ? CODE_FOR_sse_movhps + : fcode == IX86_BUILTIN_STORELPS ? CODE_FOR_sse_movlps + : fcode == IX86_BUILTIN_STOREHPD ? CODE_FOR_sse2_movhpd + : CODE_FOR_sse2_movsd); arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - op0 = expand_normal (arg0); - op1 = expand_normal (arg1); - mode0 = insn_data[icode].operand[0].mode; - mode1 = insn_data[icode].operand[1].mode; + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + mode0 = insn_data[icode].operand[1].mode; + mode1 = insn_data[icode].operand[2].mode; op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0)); - op1 = force_reg (mode1, op1); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); - pat = GEN_FCN (icode) (op0, op1); + pat = GEN_FCN (icode) (op0, op0, op1); if (! pat) return 0; emit_insn (pat); - return const0_rtx; + return 0; case IX86_BUILTIN_MOVNTPS: return ix86_expand_store_builtin (CODE_FOR_sse_movntv4sf, arglist); @@ -16120,15 +14331,15 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, return ix86_expand_store_builtin (CODE_FOR_sse_movntdi, arglist); case IX86_BUILTIN_LDMXCSR: - op0 = expand_normal (TREE_VALUE (arglist)); - target = assign_386_stack_local (SImode, SLOT_TEMP); + op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0); + target = assign_386_stack_local (SImode, 0); emit_move_insn (target, op0); - emit_insn (gen_sse_ldmxcsr (target)); + emit_insn (gen_ldmxcsr (target)); return 0; case IX86_BUILTIN_STMXCSR: - target = assign_386_stack_local (SImode, SLOT_TEMP); - emit_insn (gen_sse_stmxcsr (target)); + target = assign_386_stack_local (SImode, 0); + emit_insn (gen_stmxcsr (target)); return copy_to_mode_reg (SImode, target); case IX86_BUILTIN_SHUFPS: @@ -16139,9 +14350,9 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - op0 = expand_normal (arg0); - op1 = expand_normal (arg1); - op2 = expand_normal (arg2); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); tmode = insn_data[icode].operand[0].mode; mode0 = insn_data[icode].operand[1].mode; mode1 = insn_data[icode].operand[2].mode; @@ -16149,8 +14360,7 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) op0 = copy_to_mode_reg (mode0, op0); - if ((optimize && !register_operand (op1, mode1)) - || !(*insn_data[icode].operand[2].predicate) (op1, mode1)) + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) op1 = copy_to_mode_reg (mode1, op1); if (! (*insn_data[icode].operand[3].predicate) (op2, mode2)) { @@ -16158,7 +14368,7 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, error ("mask must be an immediate"); return gen_reg_rtx (tmode); } - if (optimize || target == 0 + if (target == 0 || GET_MODE (target) != tmode || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) target = gen_reg_rtx (tmode); @@ -16178,8 +14388,8 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, : CODE_FOR_mmx_pshufw); arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - op0 = expand_normal (arg0); - op1 = expand_normal (arg1); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); tmode = insn_data[icode].operand[0].mode; mode1 = insn_data[icode].operand[1].mode; mode2 = insn_data[icode].operand[2].mode; @@ -16202,111 +14412,14 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, emit_insn (pat); return target; - case IX86_BUILTIN_PSLLWI128: - icode = CODE_FOR_ashlv8hi3; - goto do_pshifti; - case IX86_BUILTIN_PSLLDI128: - icode = CODE_FOR_ashlv4si3; - goto do_pshifti; - case IX86_BUILTIN_PSLLQI128: - icode = CODE_FOR_ashlv2di3; - goto do_pshifti; - case IX86_BUILTIN_PSRAWI128: - icode = CODE_FOR_ashrv8hi3; - goto do_pshifti; - case IX86_BUILTIN_PSRADI128: - icode = CODE_FOR_ashrv4si3; - goto do_pshifti; - case IX86_BUILTIN_PSRLWI128: - icode = CODE_FOR_lshrv8hi3; - goto do_pshifti; - case IX86_BUILTIN_PSRLDI128: - icode = CODE_FOR_lshrv4si3; - goto do_pshifti; - case IX86_BUILTIN_PSRLQI128: - icode = CODE_FOR_lshrv2di3; - goto do_pshifti; - do_pshifti: - arg0 = TREE_VALUE (arglist); - arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); - - if (GET_CODE (op1) != CONST_INT) - { - error ("shift must be an immediate"); - return const0_rtx; - } - if (INTVAL (op1) < 0 || INTVAL (op1) > 255) - op1 = GEN_INT (255); - - tmode = insn_data[icode].operand[0].mode; - mode1 = insn_data[icode].operand[1].mode; - if (! (*insn_data[icode].operand[1].predicate) (op0, mode1)) - op0 = copy_to_reg (op0); - - target = gen_reg_rtx (tmode); - pat = GEN_FCN (icode) (target, op0, op1); - if (!pat) - return 0; - emit_insn (pat); - return target; - - case IX86_BUILTIN_PSLLW128: - icode = CODE_FOR_ashlv8hi3; - goto do_pshift; - case IX86_BUILTIN_PSLLD128: - icode = CODE_FOR_ashlv4si3; - goto do_pshift; - case IX86_BUILTIN_PSLLQ128: - icode = CODE_FOR_ashlv2di3; - goto do_pshift; - case IX86_BUILTIN_PSRAW128: - icode = CODE_FOR_ashrv8hi3; - goto do_pshift; - case IX86_BUILTIN_PSRAD128: - icode = CODE_FOR_ashrv4si3; - goto do_pshift; - case IX86_BUILTIN_PSRLW128: - icode = CODE_FOR_lshrv8hi3; - goto do_pshift; - case IX86_BUILTIN_PSRLD128: - icode = CODE_FOR_lshrv4si3; - goto do_pshift; - case IX86_BUILTIN_PSRLQ128: - icode = CODE_FOR_lshrv2di3; - goto do_pshift; - do_pshift: - arg0 = TREE_VALUE (arglist); - arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); - - tmode = insn_data[icode].operand[0].mode; - mode1 = insn_data[icode].operand[1].mode; - - if (! (*insn_data[icode].operand[1].predicate) (op0, mode1)) - op0 = copy_to_reg (op0); - - op1 = simplify_gen_subreg (TImode, op1, GET_MODE (op1), 0); - if (! (*insn_data[icode].operand[2].predicate) (op1, TImode)) - op1 = copy_to_reg (op1); - - target = gen_reg_rtx (tmode); - pat = GEN_FCN (icode) (target, op0, op1); - if (!pat) - return 0; - emit_insn (pat); - return target; - case IX86_BUILTIN_PSLLDQI128: case IX86_BUILTIN_PSRLDQI128: - icode = (fcode == IX86_BUILTIN_PSLLDQI128 ? CODE_FOR_sse2_ashlti3 + icode = ( fcode == IX86_BUILTIN_PSLLDQI128 ? CODE_FOR_sse2_ashlti3 : CODE_FOR_sse2_lshrti3); arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - op0 = expand_normal (arg0); - op1 = expand_normal (arg1); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); tmode = insn_data[icode].operand[0].mode; mode1 = insn_data[icode].operand[1].mode; mode2 = insn_data[icode].operand[2].mode; @@ -16322,99 +14435,169 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, return const0_rtx; } target = gen_reg_rtx (V2DImode); - pat = GEN_FCN (icode) (simplify_gen_subreg (tmode, target, V2DImode, 0), - op0, op1); + pat = GEN_FCN (icode) (simplify_gen_subreg (tmode, target, V2DImode, 0), op0, op1); if (! pat) return 0; emit_insn (pat); return target; case IX86_BUILTIN_FEMMS: - emit_insn (gen_mmx_femms ()); + emit_insn (gen_femms ()); return NULL_RTX; case IX86_BUILTIN_PAVGUSB: - return ix86_expand_binop_builtin (CODE_FOR_mmx_uavgv8qi3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_pavgusb, arglist, target); case IX86_BUILTIN_PF2ID: - return ix86_expand_unop_builtin (CODE_FOR_mmx_pf2id, arglist, target, 0); + return ix86_expand_unop_builtin (CODE_FOR_pf2id, arglist, target, 0); case IX86_BUILTIN_PFACC: - return ix86_expand_binop_builtin (CODE_FOR_mmx_haddv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_pfacc, arglist, target); case IX86_BUILTIN_PFADD: - return ix86_expand_binop_builtin (CODE_FOR_mmx_addv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_addv2sf3, arglist, target); case IX86_BUILTIN_PFCMPEQ: - return ix86_expand_binop_builtin (CODE_FOR_mmx_eqv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_eqv2sf3, arglist, target); case IX86_BUILTIN_PFCMPGE: - return ix86_expand_binop_builtin (CODE_FOR_mmx_gev2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_gev2sf3, arglist, target); case IX86_BUILTIN_PFCMPGT: - return ix86_expand_binop_builtin (CODE_FOR_mmx_gtv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_gtv2sf3, arglist, target); case IX86_BUILTIN_PFMAX: - return ix86_expand_binop_builtin (CODE_FOR_mmx_smaxv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_pfmaxv2sf3, arglist, target); case IX86_BUILTIN_PFMIN: - return ix86_expand_binop_builtin (CODE_FOR_mmx_sminv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_pfminv2sf3, arglist, target); case IX86_BUILTIN_PFMUL: - return ix86_expand_binop_builtin (CODE_FOR_mmx_mulv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_mulv2sf3, arglist, target); case IX86_BUILTIN_PFRCP: - return ix86_expand_unop_builtin (CODE_FOR_mmx_rcpv2sf2, arglist, target, 0); + return ix86_expand_unop_builtin (CODE_FOR_pfrcpv2sf2, arglist, target, 0); case IX86_BUILTIN_PFRCPIT1: - return ix86_expand_binop_builtin (CODE_FOR_mmx_rcpit1v2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_pfrcpit1v2sf3, arglist, target); case IX86_BUILTIN_PFRCPIT2: - return ix86_expand_binop_builtin (CODE_FOR_mmx_rcpit2v2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_pfrcpit2v2sf3, arglist, target); case IX86_BUILTIN_PFRSQIT1: - return ix86_expand_binop_builtin (CODE_FOR_mmx_rsqit1v2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_pfrsqit1v2sf3, arglist, target); case IX86_BUILTIN_PFRSQRT: - return ix86_expand_unop_builtin (CODE_FOR_mmx_rsqrtv2sf2, arglist, target, 0); + return ix86_expand_unop_builtin (CODE_FOR_pfrsqrtv2sf2, arglist, target, 0); case IX86_BUILTIN_PFSUB: - return ix86_expand_binop_builtin (CODE_FOR_mmx_subv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_subv2sf3, arglist, target); case IX86_BUILTIN_PFSUBR: - return ix86_expand_binop_builtin (CODE_FOR_mmx_subrv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_subrv2sf3, arglist, target); case IX86_BUILTIN_PI2FD: - return ix86_expand_unop_builtin (CODE_FOR_mmx_floatv2si2, arglist, target, 0); + return ix86_expand_unop_builtin (CODE_FOR_floatv2si2, arglist, target, 0); case IX86_BUILTIN_PMULHRW: - return ix86_expand_binop_builtin (CODE_FOR_mmx_pmulhrwv4hi3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_pmulhrwv4hi3, arglist, target); case IX86_BUILTIN_PF2IW: - return ix86_expand_unop_builtin (CODE_FOR_mmx_pf2iw, arglist, target, 0); + return ix86_expand_unop_builtin (CODE_FOR_pf2iw, arglist, target, 0); case IX86_BUILTIN_PFNACC: - return ix86_expand_binop_builtin (CODE_FOR_mmx_hsubv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_pfnacc, arglist, target); case IX86_BUILTIN_PFPNACC: - return ix86_expand_binop_builtin (CODE_FOR_mmx_addsubv2sf3, arglist, target); + return ix86_expand_binop_builtin (CODE_FOR_pfpnacc, arglist, target); case IX86_BUILTIN_PI2FW: - return ix86_expand_unop_builtin (CODE_FOR_mmx_pi2fw, arglist, target, 0); + return ix86_expand_unop_builtin (CODE_FOR_pi2fw, arglist, target, 0); case IX86_BUILTIN_PSWAPDSI: - return ix86_expand_unop_builtin (CODE_FOR_mmx_pswapdv2si2, arglist, target, 0); + return ix86_expand_unop_builtin (CODE_FOR_pswapdv2si2, arglist, target, 0); case IX86_BUILTIN_PSWAPDSF: - return ix86_expand_unop_builtin (CODE_FOR_mmx_pswapdv2sf2, arglist, target, 0); + return ix86_expand_unop_builtin (CODE_FOR_pswapdv2sf2, arglist, target, 0); + + case IX86_BUILTIN_SSE_ZERO: + target = gen_reg_rtx (V4SFmode); + emit_insn (gen_sse_clrv4sf (target, CONST0_RTX (V4SFmode))); + return target; + + case IX86_BUILTIN_MMX_ZERO: + target = gen_reg_rtx (DImode); + emit_insn (gen_mmx_clrdi (target)); + return target; + + case IX86_BUILTIN_CLRTI: + target = gen_reg_rtx (V2DImode); + emit_insn (gen_sse2_clrti (simplify_gen_subreg (TImode, target, V2DImode, 0))); + return target; + case IX86_BUILTIN_SQRTSD: - return ix86_expand_unop1_builtin (CODE_FOR_sse2_vmsqrtv2df2, arglist, target); + return ix86_expand_unop1_builtin (CODE_FOR_vmsqrtv2df2, arglist, target); + case IX86_BUILTIN_LOADAPD: + return ix86_expand_unop_builtin (CODE_FOR_sse2_movapd, arglist, target, 1); case IX86_BUILTIN_LOADUPD: return ix86_expand_unop_builtin (CODE_FOR_sse2_movupd, arglist, target, 1); + + case IX86_BUILTIN_STOREAPD: + return ix86_expand_store_builtin (CODE_FOR_sse2_movapd, arglist); case IX86_BUILTIN_STOREUPD: return ix86_expand_store_builtin (CODE_FOR_sse2_movupd, arglist); + case IX86_BUILTIN_LOADSD: + return ix86_expand_unop_builtin (CODE_FOR_sse2_loadsd, arglist, target, 1); + + case IX86_BUILTIN_STORESD: + return ix86_expand_store_builtin (CODE_FOR_sse2_storesd, arglist); + + case IX86_BUILTIN_SETPD1: + target = assign_386_stack_local (DFmode, 0); + arg0 = TREE_VALUE (arglist); + emit_move_insn (adjust_address (target, DFmode, 0), + expand_expr (arg0, NULL_RTX, VOIDmode, 0)); + op0 = gen_reg_rtx (V2DFmode); + emit_insn (gen_sse2_loadsd (op0, adjust_address (target, V2DFmode, 0))); + emit_insn (gen_sse2_shufpd (op0, op0, op0, GEN_INT (0))); + return op0; + + case IX86_BUILTIN_SETPD: + target = assign_386_stack_local (V2DFmode, 0); + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + emit_move_insn (adjust_address (target, DFmode, 0), + expand_expr (arg0, NULL_RTX, VOIDmode, 0)); + emit_move_insn (adjust_address (target, DFmode, 8), + expand_expr (arg1, NULL_RTX, VOIDmode, 0)); + op0 = gen_reg_rtx (V2DFmode); + emit_insn (gen_sse2_movapd (op0, target)); + return op0; + + case IX86_BUILTIN_LOADRPD: + target = ix86_expand_unop_builtin (CODE_FOR_sse2_movapd, arglist, + gen_reg_rtx (V2DFmode), 1); + emit_insn (gen_sse2_shufpd (target, target, target, GEN_INT (1))); + return target; + + case IX86_BUILTIN_LOADPD1: + target = ix86_expand_unop_builtin (CODE_FOR_sse2_loadsd, arglist, + gen_reg_rtx (V2DFmode), 1); + emit_insn (gen_sse2_shufpd (target, target, target, const0_rtx)); + return target; + + case IX86_BUILTIN_STOREPD1: + return ix86_expand_store_builtin (CODE_FOR_sse2_movapd, arglist); + case IX86_BUILTIN_STORERPD: + return ix86_expand_store_builtin (CODE_FOR_sse2_movapd, arglist); + + case IX86_BUILTIN_CLRPD: + target = gen_reg_rtx (V2DFmode); + emit_insn (gen_sse_clrv2df (target)); + return target; + case IX86_BUILTIN_MFENCE: emit_insn (gen_sse2_mfence ()); return 0; @@ -16424,7 +14607,7 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, case IX86_BUILTIN_CLFLUSH: arg0 = TREE_VALUE (arglist); - op0 = expand_normal (arg0); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); icode = CODE_FOR_sse2_clflush; if (! (*insn_data[icode].operand[0].predicate) (op0, Pmode)) op0 = copy_to_mode_reg (Pmode, op0); @@ -16439,63 +14622,54 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, case IX86_BUILTIN_MOVNTI: return ix86_expand_store_builtin (CODE_FOR_sse2_movntsi, arglist); + case IX86_BUILTIN_LOADDQA: + return ix86_expand_unop_builtin (CODE_FOR_sse2_movdqa, arglist, target, 1); case IX86_BUILTIN_LOADDQU: return ix86_expand_unop_builtin (CODE_FOR_sse2_movdqu, arglist, target, 1); + case IX86_BUILTIN_LOADD: + return ix86_expand_unop_builtin (CODE_FOR_sse2_loadd, arglist, target, 1); + + case IX86_BUILTIN_STOREDQA: + return ix86_expand_store_builtin (CODE_FOR_sse2_movdqa, arglist); case IX86_BUILTIN_STOREDQU: return ix86_expand_store_builtin (CODE_FOR_sse2_movdqu, arglist); + case IX86_BUILTIN_STORED: + return ix86_expand_store_builtin (CODE_FOR_sse2_stored, arglist); case IX86_BUILTIN_MONITOR: arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - op0 = expand_normal (arg0); - op1 = expand_normal (arg1); - op2 = expand_normal (arg2); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); if (!REG_P (op0)) - op0 = copy_to_mode_reg (Pmode, op0); + op0 = copy_to_mode_reg (SImode, op0); if (!REG_P (op1)) op1 = copy_to_mode_reg (SImode, op1); if (!REG_P (op2)) op2 = copy_to_mode_reg (SImode, op2); - if (!TARGET_64BIT) - emit_insn (gen_sse3_monitor (op0, op1, op2)); - else - emit_insn (gen_sse3_monitor64 (op0, op1, op2)); + emit_insn (gen_monitor (op0, op1, op2)); return 0; case IX86_BUILTIN_MWAIT: arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - op0 = expand_normal (arg0); - op1 = expand_normal (arg1); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); if (!REG_P (op0)) op0 = copy_to_mode_reg (SImode, op0); if (!REG_P (op1)) op1 = copy_to_mode_reg (SImode, op1); - emit_insn (gen_sse3_mwait (op0, op1)); + emit_insn (gen_mwait (op0, op1)); return 0; + case IX86_BUILTIN_LOADDDUP: + return ix86_expand_unop_builtin (CODE_FOR_loadddup, arglist, target, 1); + case IX86_BUILTIN_LDDQU: - return ix86_expand_unop_builtin (CODE_FOR_sse3_lddqu, arglist, - target, 1); - - case IX86_BUILTIN_VEC_INIT_V2SI: - case IX86_BUILTIN_VEC_INIT_V4HI: - case IX86_BUILTIN_VEC_INIT_V8QI: - return ix86_expand_vec_init_builtin (TREE_TYPE (exp), arglist, target); - - case IX86_BUILTIN_VEC_EXT_V2DF: - case IX86_BUILTIN_VEC_EXT_V2DI: - case IX86_BUILTIN_VEC_EXT_V4SF: - case IX86_BUILTIN_VEC_EXT_V4SI: - case IX86_BUILTIN_VEC_EXT_V8HI: - case IX86_BUILTIN_VEC_EXT_V2SI: - case IX86_BUILTIN_VEC_EXT_V4HI: - return ix86_expand_vec_ext_builtin (arglist, target); - - case IX86_BUILTIN_VEC_SET_V8HI: - case IX86_BUILTIN_VEC_SET_V4HI: - return ix86_expand_vec_set_builtin (arglist); + return ix86_expand_unop_builtin (CODE_FOR_lddqu, arglist, target, + 1); default: break; @@ -16505,10 +14679,14 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, if (d->code == fcode) { /* Compares are treated specially. */ - if (d->icode == CODE_FOR_sse_maskcmpv4sf3 - || d->icode == CODE_FOR_sse_vmmaskcmpv4sf3 - || d->icode == CODE_FOR_sse2_maskcmpv2df3 - || d->icode == CODE_FOR_sse2_vmmaskcmpv2df3) + if (d->icode == CODE_FOR_maskcmpv4sf3 + || d->icode == CODE_FOR_vmmaskcmpv4sf3 + || d->icode == CODE_FOR_maskncmpv4sf3 + || d->icode == CODE_FOR_vmmaskncmpv4sf3 + || d->icode == CODE_FOR_maskcmpv2df3 + || d->icode == CODE_FOR_vmmaskcmpv2df3 + || d->icode == CODE_FOR_maskncmpv2df3 + || d->icode == CODE_FOR_vmmaskncmpv2df3) return ix86_expand_sse_compare (d, arglist, target); return ix86_expand_binop_builtin (d->icode, arglist, target); @@ -16522,7 +14700,8 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, if (d->code == fcode) return ix86_expand_sse_comi (d, arglist, target); - gcc_unreachable (); + /* @@@ Should really do something sensible here. */ + return 0; } /* Store OPERAND to the memory after reload is completed. This means @@ -16531,8 +14710,8 @@ rtx ix86_force_to_memory (enum machine_mode mode, rtx operand) { rtx result; - - gcc_assert (reload_completed); + if (!reload_completed) + abort (); if (TARGET_RED_ZONE) { result = gen_rtx_MEM (mode, @@ -16558,7 +14737,7 @@ ix86_force_to_memory (enum machine_mode mode, rtx operand) operand)); break; default: - gcc_unreachable (); + abort (); } result = gen_rtx_MEM (mode, stack_pointer_rtx); } @@ -16585,8 +14764,9 @@ ix86_force_to_memory (enum machine_mode mode, rtx operand) } break; case HImode: - /* Store HImodes as SImodes. */ - operand = gen_lowpart (SImode, operand); + /* It is better to store HImodes as SImodes. */ + if (!TARGET_PARTIAL_REG_STALL) + operand = gen_lowpart (SImode, operand); /* FALLTHRU */ case SImode: emit_insn ( @@ -16597,7 +14777,7 @@ ix86_force_to_memory (enum machine_mode mode, rtx operand) operand)); break; default: - gcc_unreachable (); + abort (); } result = gen_rtx_MEM (mode, stack_pointer_rtx); } @@ -16614,6 +14794,8 @@ ix86_free_from_memory (enum machine_mode mode) if (mode == DImode || TARGET_64BIT) size = 8; + else if (mode == HImode && TARGET_PARTIAL_REG_STALL) + size = 2; else size = 4; /* Use LEA to deallocate stack space. In peephole2 it will be converted @@ -16631,99 +14813,34 @@ ix86_free_from_memory (enum machine_mode mode) enum reg_class ix86_preferred_reload_class (rtx x, enum reg_class class) { - enum machine_mode mode = GET_MODE (x); - - /* We're only allowed to return a subclass of CLASS. Many of the - following checks fail for NO_REGS, so eliminate that early. */ - if (class == NO_REGS) + if (GET_CODE (x) == CONST_VECTOR && x != CONST0_RTX (GET_MODE (x))) return NO_REGS; - - /* All classes can load zeros. */ - if (x == CONST0_RTX (mode)) - return class; - - /* Force constants into memory if we are loading a (nonzero) constant into - an MMX or SSE register. This is because there are no MMX/SSE instructions - to load from a constant. */ - if (CONSTANT_P (x) - && (MAYBE_MMX_CLASS_P (class) || MAYBE_SSE_CLASS_P (class))) - return NO_REGS; - - /* Prefer SSE regs only, if we can use them for math. */ - if (TARGET_SSE_MATH && !TARGET_MIX_SSE_I387 && SSE_FLOAT_MODE_P (mode)) - return SSE_CLASS_P (class) ? class : NO_REGS; - - /* Floating-point constants need more complex checks. */ if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode) { - /* General regs can load everything. */ - if (reg_class_subset_p (class, GENERAL_REGS)) - return class; - - /* Floats can load 0 and 1 plus some others. Note that we eliminated - zero above. We only want to wind up preferring 80387 registers if - we plan on doing computation with them. */ - if (TARGET_80387 - && standard_80387_constant_p (x)) + /* SSE can't load any constant directly yet. */ + if (SSE_CLASS_P (class)) + return NO_REGS; + /* Floats can load 0 and 1. */ + if (MAYBE_FLOAT_CLASS_P (class) && standard_80387_constant_p (x)) { - /* Limit class to non-sse. */ - if (class == FLOAT_SSE_REGS) - return FLOAT_REGS; - if (class == FP_TOP_SSE_REGS) - return FP_TOP_REG; - if (class == FP_SECOND_SSE_REGS) - return FP_SECOND_REG; - if (class == FLOAT_INT_REGS || class == FLOAT_REGS) + /* Limit class to non-SSE. Use GENERAL_REGS if possible. */ + if (MAYBE_SSE_CLASS_P (class)) + return (reg_class_subset_p (class, GENERAL_REGS) + ? GENERAL_REGS : FLOAT_REGS); + else return class; } - - return NO_REGS; - } - - /* Generally when we see PLUS here, it's the function invariant - (plus soft-fp const_int). Which can only be computed into general - regs. */ - if (GET_CODE (x) == PLUS) - return reg_class_subset_p (class, GENERAL_REGS) ? class : NO_REGS; - - /* QImode constants are easy to load, but non-constant QImode data - must go into Q_REGS. */ - if (GET_MODE (x) == QImode && !CONSTANT_P (x)) - { - if (reg_class_subset_p (class, Q_REGS)) - return class; - if (reg_class_subset_p (Q_REGS, class)) - return Q_REGS; - return NO_REGS; - } - - return class; -} - -/* Discourage putting floating-point values in SSE registers unless - SSE math is being used, and likewise for the 387 registers. */ -enum reg_class -ix86_preferred_output_reload_class (rtx x, enum reg_class class) -{ - enum machine_mode mode = GET_MODE (x); - - /* Restrict the output reload class to the register bank that we are doing - math on. If we would like not to return a subset of CLASS, reject this - alternative: if reload cannot do this, it will still use its choice. */ - mode = GET_MODE (x); - if (TARGET_SSE_MATH && SSE_FLOAT_MODE_P (mode)) - return MAYBE_SSE_CLASS_P (class) ? SSE_REGS : NO_REGS; - - if (TARGET_80387 && SCALAR_FLOAT_MODE_P (mode)) - { - if (class == FP_TOP_SSE_REGS) - return FP_TOP_REG; - else if (class == FP_SECOND_SSE_REGS) - return FP_SECOND_REG; - else - return FLOAT_CLASS_P (class) ? class : NO_REGS; + /* General regs can load everything. */ + if (reg_class_subset_p (class, GENERAL_REGS)) + return GENERAL_REGS; + /* In case we haven't resolved FLOAT or SSE yet, give up. */ + if (MAYBE_FLOAT_CLASS_P (class) || MAYBE_SSE_CLASS_P (class)) + return NO_REGS; } - + if (MAYBE_MMX_CLASS_P (class) && CONSTANT_P (x)) + return NO_REGS; + if (GET_MODE (x) == QImode && ! reg_class_subset_p (class, Q_REGS)) + return Q_REGS; return class; } @@ -16737,7 +14854,6 @@ ix86_preferred_output_reload_class (rtx x, enum reg_class class) When STRICT is false, we are being called from REGISTER_MOVE_COST, so do not enforce these sanity checks. */ - int ix86_secondary_memory_needed (enum reg_class class1, enum reg_class class2, enum machine_mode mode, int strict) @@ -16749,86 +14865,23 @@ ix86_secondary_memory_needed (enum reg_class class1, enum reg_class class2, || MAYBE_MMX_CLASS_P (class1) != MMX_CLASS_P (class1) || MAYBE_MMX_CLASS_P (class2) != MMX_CLASS_P (class2)) { - gcc_assert (!strict); - return true; - } - - if (FLOAT_CLASS_P (class1) != FLOAT_CLASS_P (class2)) - return true; - - /* ??? This is a lie. We do have moves between mmx/general, and for - mmx/sse2. But by saying we need secondary memory we discourage the - register allocator from using the mmx registers unless needed. */ - if (MMX_CLASS_P (class1) != MMX_CLASS_P (class2)) - return true; - - if (SSE_CLASS_P (class1) != SSE_CLASS_P (class2)) - { - /* SSE1 doesn't have any direct moves from other classes. */ - if (!TARGET_SSE2) - return true; - - /* If the target says that inter-unit moves are more expensive - than moving through memory, then don't generate them. */ - if (!TARGET_INTER_UNIT_MOVES && !optimize_size) - return true; - - /* Between SSE and general, we have moves no larger than word size. */ - if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) - return true; - - /* ??? For the cost of one register reformat penalty, we could use - the same instructions to move SFmode and DFmode data, but the - relevant move patterns don't support those alternatives. */ - if (mode == SFmode || mode == DFmode) - return true; - } - - return false; -} - -/* Return true if the registers in CLASS cannot represent the change from - modes FROM to TO. */ - -bool -ix86_cannot_change_mode_class (enum machine_mode from, enum machine_mode to, - enum reg_class class) -{ - if (from == to) - return false; - - /* x87 registers can't do subreg at all, as all values are reformatted - to extended precision. */ - if (MAYBE_FLOAT_CLASS_P (class)) - return true; - - if (MAYBE_SSE_CLASS_P (class) || MAYBE_MMX_CLASS_P (class)) - { - /* Vector registers do not support QI or HImode loads. If we don't - disallow a change to these modes, reload will assume it's ok to - drop the subreg from (subreg:SI (reg:HI 100) 0). This affects - the vec_dupv4hi pattern. */ - if (GET_MODE_SIZE (from) < 4) - return true; - - /* Vector registers do not support subreg with nonzero offsets, which - are otherwise valid for integer registers. Since we can't see - whether we have a nonzero offset from here, prohibit all - nonparadoxical subregs changing size. */ - if (GET_MODE_SIZE (to) < GET_MODE_SIZE (from)) - return true; + if (strict) + abort (); + else + return 1; } - - return false; + return (FLOAT_CLASS_P (class1) != FLOAT_CLASS_P (class2) + || ((SSE_CLASS_P (class1) != SSE_CLASS_P (class2) + || MMX_CLASS_P (class1) != MMX_CLASS_P (class2)) + && ((mode != SImode && (mode != DImode || !TARGET_64BIT)) + || (!TARGET_INTER_UNIT_MOVES && !optimize_size)))); } - /* Return the cost of moving data from a register in class CLASS1 to one in class CLASS2. It is not required that the cost always equal 2 when FROM is the same as TO; on some machines it is expensive to move between registers if they are not general registers. */ - int ix86_register_move_cost (enum machine_mode mode, enum reg_class class1, enum reg_class class2) @@ -16875,8 +14928,7 @@ ix86_register_move_cost (enum machine_mode mode, enum reg_class class1, } /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */ - -bool +int ix86_hard_regno_mode_ok (int regno, enum machine_mode mode) { /* Flags and only flags can only hold CCmode values. */ @@ -16890,9 +14942,15 @@ ix86_hard_regno_mode_ok (int regno, enum machine_mode mode) return VALID_FP_MODE_P (mode); if (SSE_REGNO_P (regno)) { + /* HACK! We didn't change all of the constraints for SSE1 for the + scalar modes on the branch. Fortunately, they're not required + for ABI compatibility. */ + if (!TARGET_SSE2 && !VECTOR_MODE_P (mode)) + return VALID_SSE_REG_MODE (mode); + /* We implement the move patterns for all vector modes into and - out of SSE registers, even when no operation instructions - are available. */ + out of SSE registers, even when no operation instructions + are available. */ return (VALID_SSE_REG_MODE (mode) || VALID_SSE2_REG_MODE (mode) || VALID_MMX_REG_MODE (mode) @@ -16901,98 +14959,20 @@ ix86_hard_regno_mode_ok (int regno, enum machine_mode mode) if (MMX_REGNO_P (regno)) { /* We implement the move patterns for 3DNOW modes even in MMX mode, - so if the register is available at all, then we can move data of - the given mode into or out of it. */ + so if the register is available at all, then we can move data of + the given mode into or out of it. */ return (VALID_MMX_REG_MODE (mode) || VALID_MMX_REG_MODE_3DNOW (mode)); } - - if (mode == QImode) - { - /* Take care for QImode values - they can be in non-QI regs, - but then they do cause partial register stalls. */ - if (regno < 4 || TARGET_64BIT) - return 1; - if (!TARGET_PARTIAL_REG_STALL) - return 1; - return reload_in_progress || reload_completed; - } - /* We handle both integer and floats in the general purpose registers. */ - else if (VALID_INT_MODE_P (mode)) - return 1; - else if (VALID_FP_MODE_P (mode)) - return 1; - /* Lots of MMX code casts 8 byte vector modes to DImode. If we then go - on to use that value in smaller contexts, this can easily force a - pseudo to be allocated to GENERAL_REGS. Since this is no worse than - supporting DImode, allow it. */ - else if (VALID_MMX_REG_MODE_3DNOW (mode) || VALID_MMX_REG_MODE (mode)) + /* We handle both integer and floats in the general purpose registers. + In future we should be able to handle vector modes as well. */ + if (!VALID_INT_MODE_P (mode) && !VALID_FP_MODE_P (mode)) + return 0; + /* Take care for QImode values - they can be in non-QI regs, but then + they do cause partial register stalls. */ + if (regno < 4 || mode != QImode || TARGET_64BIT) return 1; - - return 0; -} - -/* A subroutine of ix86_modes_tieable_p. Return true if MODE is a - tieable integer mode. */ - -static bool -ix86_tieable_integer_mode_p (enum machine_mode mode) -{ - switch (mode) - { - case HImode: - case SImode: - return true; - - case QImode: - return TARGET_64BIT || !TARGET_PARTIAL_REG_STALL; - - case DImode: - return TARGET_64BIT; - - default: - return false; - } -} - -/* Return true if MODE1 is accessible in a register that can hold MODE2 - without copying. That is, all register classes that can hold MODE2 - can also hold MODE1. */ - -bool -ix86_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2) -{ - if (mode1 == mode2) - return true; - - if (ix86_tieable_integer_mode_p (mode1) - && ix86_tieable_integer_mode_p (mode2)) - return true; - - /* MODE2 being XFmode implies fp stack or general regs, which means we - can tie any smaller floating point modes to it. Note that we do not - tie this with TFmode. */ - if (mode2 == XFmode) - return mode1 == SFmode || mode1 == DFmode; - - /* MODE2 being DFmode implies fp stack, general or sse regs, which means - that we can tie it with SFmode. */ - if (mode2 == DFmode) - return mode1 == SFmode; - - /* If MODE2 is only appropriate for an SSE register, then tie with - any other mode acceptable to SSE registers. */ - if (GET_MODE_SIZE (mode2) >= 8 - && ix86_hard_regno_mode_ok (FIRST_SSE_REG, mode2)) - return ix86_hard_regno_mode_ok (FIRST_SSE_REG, mode1); - - /* If MODE2 is appropriate for an MMX (or SSE) register, then tie - with any other mode acceptable to MMX registers. */ - if (GET_MODE_SIZE (mode2) == 8 - && ix86_hard_regno_mode_ok (FIRST_MMX_REG, mode2)) - return ix86_hard_regno_mode_ok (FIRST_MMX_REG, mode1); - - return false; + return reload_in_progress || reload_completed || !TARGET_PARTIAL_REG_STALL; } /* Return the cost of moving data of mode M between a @@ -17100,9 +15080,9 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) case CONST: case LABEL_REF: case SYMBOL_REF: - if (TARGET_64BIT && !x86_64_immediate_operand (x, VOIDmode)) + if (TARGET_64BIT && !x86_64_sign_extended_value (x)) *total = 3; - else if (TARGET_64BIT && !x86_64_zext_immediate_operand (x, VOIDmode)) + else if (TARGET_64BIT && !x86_64_zero_extended_value (x)) *total = 2; else if (flag_pic && SYMBOLIC_CONST (x) && (!TARGET_64BIT @@ -17144,13 +15124,13 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) && GET_MODE (XEXP (x, 0)) == SImode) *total = 1; else if (TARGET_ZERO_EXTEND_WITH_AND) - *total = ix86_cost->add; + *total = COSTS_N_INSNS (ix86_cost->add); else - *total = ix86_cost->movzx; + *total = COSTS_N_INSNS (ix86_cost->movzx); return false; case SIGN_EXTEND: - *total = ix86_cost->movsx; + *total = COSTS_N_INSNS (ix86_cost->movsx); return false; case ASHIFT: @@ -17160,13 +15140,14 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) HOST_WIDE_INT value = INTVAL (XEXP (x, 1)); if (value == 1) { - *total = ix86_cost->add; + *total = COSTS_N_INSNS (ix86_cost->add); return false; } if ((value == 2 || value == 3) + && !TARGET_DECOMPOSE_LEA && ix86_cost->lea <= ix86_cost->shift_const) { - *total = ix86_cost->lea; + *total = COSTS_N_INSNS (ix86_cost->lea); return false; } } @@ -17181,92 +15162,64 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) if (GET_CODE (XEXP (x, 1)) == CONST_INT) { if (INTVAL (XEXP (x, 1)) > 32) - *total = ix86_cost->shift_const + COSTS_N_INSNS (2); + *total = COSTS_N_INSNS(ix86_cost->shift_const + 2); else - *total = ix86_cost->shift_const * 2; + *total = COSTS_N_INSNS(ix86_cost->shift_const * 2); } else { if (GET_CODE (XEXP (x, 1)) == AND) - *total = ix86_cost->shift_var * 2; + *total = COSTS_N_INSNS(ix86_cost->shift_var * 2); else - *total = ix86_cost->shift_var * 6 + COSTS_N_INSNS (2); + *total = COSTS_N_INSNS(ix86_cost->shift_var * 6 + 2); } } else { if (GET_CODE (XEXP (x, 1)) == CONST_INT) - *total = ix86_cost->shift_const; + *total = COSTS_N_INSNS (ix86_cost->shift_const); else - *total = ix86_cost->shift_var; + *total = COSTS_N_INSNS (ix86_cost->shift_var); } return false; case MULT: if (FLOAT_MODE_P (mode)) + *total = COSTS_N_INSNS (ix86_cost->fmul); + else if (GET_CODE (XEXP (x, 1)) == CONST_INT) { - *total = ix86_cost->fmul; - return false; - } - else - { - rtx op0 = XEXP (x, 0); - rtx op1 = XEXP (x, 1); + unsigned HOST_WIDE_INT value = INTVAL (XEXP (x, 1)); int nbits; - if (GET_CODE (XEXP (x, 1)) == CONST_INT) - { - unsigned HOST_WIDE_INT value = INTVAL (XEXP (x, 1)); - for (nbits = 0; value != 0; value &= value - 1) - nbits++; - } - else - /* This is arbitrary. */ - nbits = 7; - /* Compute costs correctly for widening multiplication. */ - if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op1) == ZERO_EXTEND) - && GET_MODE_SIZE (GET_MODE (XEXP (op0, 0))) * 2 - == GET_MODE_SIZE (mode)) - { - int is_mulwiden = 0; - enum machine_mode inner_mode = GET_MODE (op0); - - if (GET_CODE (op0) == GET_CODE (op1)) - is_mulwiden = 1, op1 = XEXP (op1, 0); - else if (GET_CODE (op1) == CONST_INT) - { - if (GET_CODE (op0) == SIGN_EXTEND) - is_mulwiden = trunc_int_for_mode (INTVAL (op1), inner_mode) - == INTVAL (op1); - else - is_mulwiden = !(INTVAL (op1) & ~GET_MODE_MASK (inner_mode)); - } + for (nbits = 0; value != 0; value >>= 1) + nbits++; - if (is_mulwiden) - op0 = XEXP (op0, 0), mode = GET_MODE (op0); - } - - *total = (ix86_cost->mult_init[MODE_INDEX (mode)] - + nbits * ix86_cost->mult_bit - + rtx_cost (op0, outer_code) + rtx_cost (op1, outer_code)); - - return true; + *total = COSTS_N_INSNS (ix86_cost->mult_init[MODE_INDEX (mode)] + + nbits * ix86_cost->mult_bit); + } + else + { + /* This is arbitrary */ + *total = COSTS_N_INSNS (ix86_cost->mult_init[MODE_INDEX (mode)] + + 7 * ix86_cost->mult_bit); } + return false; case DIV: case UDIV: case MOD: case UMOD: if (FLOAT_MODE_P (mode)) - *total = ix86_cost->fdiv; + *total = COSTS_N_INSNS (ix86_cost->fdiv); else - *total = ix86_cost->divide[MODE_INDEX (mode)]; + *total = COSTS_N_INSNS (ix86_cost->divide[MODE_INDEX (mode)]); return false; case PLUS: if (FLOAT_MODE_P (mode)) - *total = ix86_cost->fadd; - else if (GET_MODE_CLASS (mode) == MODE_INT + *total = COSTS_N_INSNS (ix86_cost->fadd); + else if (!TARGET_DECOMPOSE_LEA + && GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_BITSIZE (mode) <= GET_MODE_BITSIZE (Pmode)) { if (GET_CODE (XEXP (x, 0)) == PLUS @@ -17277,7 +15230,7 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) HOST_WIDE_INT val = INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)); if (val == 2 || val == 4 || val == 8) { - *total = ix86_cost->lea; + *total = COSTS_N_INSNS (ix86_cost->lea); *total += rtx_cost (XEXP (XEXP (x, 0), 1), outer_code); *total += rtx_cost (XEXP (XEXP (XEXP (x, 0), 0), 0), outer_code); @@ -17291,7 +15244,7 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) HOST_WIDE_INT val = INTVAL (XEXP (XEXP (x, 0), 1)); if (val == 2 || val == 4 || val == 8) { - *total = ix86_cost->lea; + *total = COSTS_N_INSNS (ix86_cost->lea); *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code); *total += rtx_cost (XEXP (x, 1), outer_code); return true; @@ -17299,7 +15252,7 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) } else if (GET_CODE (XEXP (x, 0)) == PLUS) { - *total = ix86_cost->lea; + *total = COSTS_N_INSNS (ix86_cost->lea); *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code); *total += rtx_cost (XEXP (XEXP (x, 0), 1), outer_code); *total += rtx_cost (XEXP (x, 1), outer_code); @@ -17311,7 +15264,7 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) case MINUS: if (FLOAT_MODE_P (mode)) { - *total = ix86_cost->fadd; + *total = COSTS_N_INSNS (ix86_cost->fadd); return false; } /* FALLTHRU */ @@ -17321,7 +15274,7 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) case XOR: if (!TARGET_64BIT && mode == DImode) { - *total = (ix86_cost->add * 2 + *total = (COSTS_N_INSNS (ix86_cost->add) * 2 + (rtx_cost (XEXP (x, 0), outer_code) << (GET_MODE (XEXP (x, 0)) != DImode)) + (rtx_cost (XEXP (x, 1), outer_code) @@ -17333,63 +15286,33 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) case NEG: if (FLOAT_MODE_P (mode)) { - *total = ix86_cost->fchs; + *total = COSTS_N_INSNS (ix86_cost->fchs); return false; } /* FALLTHRU */ case NOT: if (!TARGET_64BIT && mode == DImode) - *total = ix86_cost->add * 2; + *total = COSTS_N_INSNS (ix86_cost->add * 2); else - *total = ix86_cost->add; - return false; - - case COMPARE: - if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT - && XEXP (XEXP (x, 0), 1) == const1_rtx - && GET_CODE (XEXP (XEXP (x, 0), 2)) == CONST_INT - && XEXP (x, 1) == const0_rtx) - { - /* This kind of construct is implemented using test[bwl]. - Treat it as if we had an AND. */ - *total = (ix86_cost->add - + rtx_cost (XEXP (XEXP (x, 0), 0), outer_code) - + rtx_cost (const1_rtx, outer_code)); - return true; - } + *total = COSTS_N_INSNS (ix86_cost->add); return false; case FLOAT_EXTEND: if (!TARGET_SSE_MATH || mode == XFmode || (mode == DFmode && !TARGET_SSE2)) - /* For standard 80387 constants, raise the cost to prevent - compress_float_constant() to generate load from memory. */ - switch (standard_80387_constant_p (XEXP (x, 0))) - { - case -1: - case 0: - *total = 0; - break; - case 1: /* 0.0 */ - *total = 1; - break; - default: - *total = (x86_ext_80387_constants & TUNEMASK - || optimize_size - ? 1 : 0); - } + *total = 0; return false; case ABS: if (FLOAT_MODE_P (mode)) - *total = ix86_cost->fabs; + *total = COSTS_N_INSNS (ix86_cost->fabs); return false; case SQRT: if (FLOAT_MODE_P (mode)) - *total = ix86_cost->fsqrt; + *total = COSTS_N_INSNS (ix86_cost->fsqrt); return false; case UNSPEC: @@ -17402,6 +15325,17 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) } } +#if defined (DO_GLOBAL_CTORS_BODY) && defined (HAS_INIT_SECTION) +static void +ix86_svr3_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED) +{ + init_section (); + fputs ("\tpushl $", asm_out_file); + assemble_name (asm_out_file, XSTR (symbol, 0)); + fputc ('\n', asm_out_file); +} +#endif + #if TARGET_MACHO static int current_machopic_label_num; @@ -17416,9 +15350,6 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) char *binder_name, *symbol_name, lazy_ptr_name[32]; int label = ++current_machopic_label_num; - /* For 64-bit we shouldn't get here. */ - gcc_assert (!TARGET_64BIT); - /* Lose our funky encoding stuff so it doesn't contaminate the stub. */ symb = (*targetm.strip_name_encoding) (symb); @@ -17433,46 +15364,39 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) sprintf (lazy_ptr_name, "L%d$lz", label); if (MACHOPIC_PURE) - switch_to_section (darwin_sections[machopic_picsymbol_stub_section]); + machopic_picsymbol_stub_section (); else - switch_to_section (darwin_sections[machopic_symbol_stub_section]); + machopic_symbol_stub_section (); fprintf (file, "%s:\n", stub); fprintf (file, "\t.indirect_symbol %s\n", symbol_name); if (MACHOPIC_PURE) { - fprintf (file, "\tcall\tLPC$%d\nLPC$%d:\tpopl\t%%eax\n", label, label); - fprintf (file, "\tmovl\t%s-LPC$%d(%%eax),%%edx\n", lazy_ptr_name, label); - fprintf (file, "\tjmp\t*%%edx\n"); + fprintf (file, "\tcall LPC$%d\nLPC$%d:\tpopl %%eax\n", label, label); + fprintf (file, "\tmovl %s-LPC$%d(%%eax),%%edx\n", lazy_ptr_name, label); + fprintf (file, "\tjmp %%edx\n"); } else - fprintf (file, "\tjmp\t*%s\n", lazy_ptr_name); + fprintf (file, "\tjmp *%s\n", lazy_ptr_name); fprintf (file, "%s:\n", binder_name); if (MACHOPIC_PURE) { - fprintf (file, "\tlea\t%s-LPC$%d(%%eax),%%eax\n", lazy_ptr_name, label); - fprintf (file, "\tpushl\t%%eax\n"); + fprintf (file, "\tlea %s-LPC$%d(%%eax),%%eax\n", lazy_ptr_name, label); + fprintf (file, "\tpushl %%eax\n"); } else - fprintf (file, "\tpushl\t$%s\n", lazy_ptr_name); + fprintf (file, "\t pushl $%s\n", lazy_ptr_name); - fprintf (file, "\tjmp\tdyld_stub_binding_helper\n"); + fprintf (file, "\tjmp dyld_stub_binding_helper\n"); - switch_to_section (darwin_sections[machopic_lazy_symbol_ptr_section]); + machopic_lazy_symbol_ptr_section (); fprintf (file, "%s:\n", lazy_ptr_name); fprintf (file, "\t.indirect_symbol %s\n", symbol_name); fprintf (file, "\t.long %s\n", binder_name); } - -void -darwin_x86_file_end (void) -{ - darwin_file_end (); - ix86_file_end (); -} #endif /* TARGET_MACHO */ /* Order the registers for register allocator. */ @@ -17519,6 +15443,10 @@ x86_order_regs_for_local_alloc (void) reg_alloc_order [pos++] = 0; } +#ifndef TARGET_USE_MS_BITFIELD_LAYOUT +#define TARGET_USE_MS_BITFIELD_LAYOUT 0 +#endif + /* Handle a "ms_struct" or "gcc_struct" attribute; arguments as in struct attribute_spec.handler. */ static tree @@ -17538,8 +15466,7 @@ ix86_handle_struct_attribute (tree *node, tree name, if (!(type && (TREE_CODE (*type) == RECORD_TYPE || TREE_CODE (*type) == UNION_TYPE))) { - warning (OPT_Wattributes, "%qs attribute ignored", - IDENTIFIER_POINTER (name)); + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -17548,7 +15475,7 @@ ix86_handle_struct_attribute (tree *node, tree name, || ((is_attribute_p ("gcc_struct", name) && lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (*type))))) { - warning (OPT_Wattributes, "%qs incompatible attribute ignored", + warning ("`%s' incompatible attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } @@ -17559,7 +15486,7 @@ ix86_handle_struct_attribute (tree *node, tree name, static bool ix86_ms_bitfield_layout_p (tree record_type) { - return (TARGET_MS_BITFIELD_LAYOUT && + return (TARGET_USE_MS_BITFIELD_LAYOUT && !lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (record_type))) || lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (record_type)); } @@ -17749,10 +15676,8 @@ x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED, #if TARGET_MACHO if (TARGET_MACHO) { - rtx sym_ref = XEXP (DECL_RTL (function), 0); - tmp = (gen_rtx_SYMBOL_REF - (Pmode, - machopic_indirection_name (sym_ref, /*stub_p=*/true))); + const char *ip = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)); + tmp = gen_rtx_SYMBOL_REF (Pmode, machopic_stub_name (ip)); tmp = gen_rtx_MEM (QImode, tmp); xops[0] = tmp; output_asm_insn ("jmp\t%0", xops); @@ -17761,7 +15686,7 @@ x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED, #endif /* TARGET_MACHO */ { tmp = gen_rtx_REG (SImode, 2 /* ECX */); - output_set_got (tmp, NULL_RTX); + output_set_got (tmp); xops[1] = tmp; output_asm_insn ("mov{l}\t{%0@GOT(%1), %1|%1, %0@GOT[%1]}", xops); @@ -17774,9 +15699,6 @@ static void x86_file_start (void) { default_file_start (); -#if TARGET_MACHO - darwin_file_start (); -#endif if (X86_FILE_START_VERSION_DIRECTIVE) fputs ("\t.version\t\"01.01\"\n", asm_out_file); if (X86_FILE_START_FLTUSED) @@ -17890,7 +15812,7 @@ min_insn_size (rtx insn) window. */ static void -ix86_avoid_jump_misspredicts (void) +k8_avoid_jump_misspredicts (void) { rtx insn, start = get_insns (); int nbytes = 0, njumps = 0; @@ -17910,8 +15832,8 @@ ix86_avoid_jump_misspredicts (void) { nbytes += min_insn_size (insn); - if (dump_file) - fprintf(dump_file, "Insn %i estimated to %i bytes\n", + if (rtl_dump_file) + fprintf(rtl_dump_file, "Insn %i estimated to %i bytes\n", INSN_UID (insn), min_insn_size (insn)); if ((GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) != ADDR_VEC @@ -17933,85 +15855,75 @@ ix86_avoid_jump_misspredicts (void) isjump = 0; nbytes -= min_insn_size (start); } - gcc_assert (njumps >= 0); - if (dump_file) - fprintf (dump_file, "Interval %i to %i has %i bytes\n", + if (njumps < 0) + abort (); + if (rtl_dump_file) + fprintf(rtl_dump_file, "Interval %i to %i has %i bytes\n", INSN_UID (start), INSN_UID (insn), nbytes); if (njumps == 3 && isjump && nbytes < 16) { int padsize = 15 - nbytes + min_insn_size (insn); - if (dump_file) - fprintf (dump_file, "Padding insn %i by %i bytes!\n", - INSN_UID (insn), padsize); + if (rtl_dump_file) + fprintf (rtl_dump_file, "Padding insn %i by %i bytes!\n", INSN_UID (insn), padsize); emit_insn_before (gen_align (GEN_INT (padsize)), insn); } } } -/* AMD Athlon works faster +/* Implement machine specific optimizations. + At the moment we implement single transformation: AMD Athlon works faster when RET is not destination of conditional jump or directly preceded by other jump instruction. We avoid the penalty by inserting NOP just before the RET instructions in such cases. */ static void -ix86_pad_returns (void) +ix86_reorg (void) { edge e; - edge_iterator ei; - FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) - { - basic_block bb = e->src; - rtx ret = BB_END (bb); - rtx prev; - bool replace = false; - - if (GET_CODE (ret) != JUMP_INSN || GET_CODE (PATTERN (ret)) != RETURN - || !maybe_hot_bb_p (bb)) - continue; - for (prev = PREV_INSN (ret); prev; prev = PREV_INSN (prev)) - if (active_insn_p (prev) || GET_CODE (prev) == CODE_LABEL) - break; - if (prev && GET_CODE (prev) == CODE_LABEL) - { - edge e; - edge_iterator ei; - - FOR_EACH_EDGE (e, ei, bb->preds) - if (EDGE_FREQUENCY (e) && e->src->index >= 0 - && !(e->flags & EDGE_FALLTHRU)) - replace = true; - } - if (!replace) - { - prev = prev_active_insn (ret); - if (prev - && ((GET_CODE (prev) == JUMP_INSN && any_condjump_p (prev)) - || GET_CODE (prev) == CALL_INSN)) - replace = true; - /* Empty functions get branch mispredict even when the jump destination - is not visible to us. */ - if (!prev && cfun->function_frequency > FUNCTION_FREQUENCY_UNLIKELY_EXECUTED) + if (!TARGET_ATHLON_K8 || !optimize || optimize_size) + return; + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) + { + basic_block bb = e->src; + rtx ret = BB_END (bb); + rtx prev; + bool replace = false; + + if (GET_CODE (ret) != JUMP_INSN || GET_CODE (PATTERN (ret)) != RETURN + || !maybe_hot_bb_p (bb)) + continue; + for (prev = PREV_INSN (ret); prev; prev = PREV_INSN (prev)) + if (active_insn_p (prev) || GET_CODE (prev) == CODE_LABEL) + break; + if (prev && GET_CODE (prev) == CODE_LABEL) + { + edge e; + for (e = bb->pred; e; e = e->pred_next) + if (EDGE_FREQUENCY (e) && e->src->index >= 0 + && !(e->flags & EDGE_FALLTHRU)) replace = true; - } - if (replace) - { - emit_insn_before (gen_return_internal_long (), ret); - delete_insn (ret); - } - } -} - -/* Implement machine specific optimizations. We implement padding of returns - for K8 CPUs and pass to avoid 4 jumps in the single 16 byte window. */ -static void -ix86_reorg (void) -{ - if (TARGET_PAD_RETURNS && optimize && !optimize_size) - ix86_pad_returns (); - if (TARGET_FOUR_JUMP_LIMIT && optimize && !optimize_size) - ix86_avoid_jump_misspredicts (); + } + if (!replace) + { + prev = prev_active_insn (ret); + if (prev + && ((GET_CODE (prev) == JUMP_INSN && any_condjump_p (prev)) + || GET_CODE (prev) == CALL_INSN)) + replace = true; + /* Empty functions get branch mispredict even when the jump destination + is not visible to us. */ + if (!prev && cfun->function_frequency > FUNCTION_FREQUENCY_UNLIKELY_EXECUTED) + replace = true; + } + if (replace) + { + emit_insn_before (gen_return_internal_long (), ret); + delete_insn (ret); + } + } + k8_avoid_jump_misspredicts (); } /* Return nonzero when QImode register that must be represented via REX prefix @@ -18058,7 +15970,9 @@ x86_emit_floatuns (rtx operands[2]) enum machine_mode mode, inmode; inmode = GET_MODE (operands[1]); - gcc_assert (inmode == SImode || inmode == DImode); + if (inmode != SImode + && inmode != DImode) + abort (); out = operands[0]; in = force_reg (inmode, operands[1]); @@ -18084,1076 +15998,102 @@ x86_emit_floatuns (rtx operands[2]) emit_label (donelab); } - -/* A subroutine of ix86_expand_vector_init. Store into TARGET a vector - with all elements equal to VAR. Return true if successful. */ - -static bool -ix86_expand_vector_init_duplicate (bool mmx_ok, enum machine_mode mode, - rtx target, rtx val) -{ - enum machine_mode smode, wsmode, wvmode; - rtx x; - - switch (mode) - { - case V2SImode: - case V2SFmode: - if (!mmx_ok) - return false; - /* FALLTHRU */ - - case V2DFmode: - case V2DImode: - case V4SFmode: - case V4SImode: - val = force_reg (GET_MODE_INNER (mode), val); - x = gen_rtx_VEC_DUPLICATE (mode, val); - emit_insn (gen_rtx_SET (VOIDmode, target, x)); - return true; - - case V4HImode: - if (!mmx_ok) - return false; - if (TARGET_SSE || TARGET_3DNOW_A) - { - val = gen_lowpart (SImode, val); - x = gen_rtx_TRUNCATE (HImode, val); - x = gen_rtx_VEC_DUPLICATE (mode, x); - emit_insn (gen_rtx_SET (VOIDmode, target, x)); - return true; - } - else - { - smode = HImode; - wsmode = SImode; - wvmode = V2SImode; - goto widen; - } - - case V8QImode: - if (!mmx_ok) - return false; - smode = QImode; - wsmode = HImode; - wvmode = V4HImode; - goto widen; - case V8HImode: - if (TARGET_SSE2) - { - rtx tmp1, tmp2; - /* Extend HImode to SImode using a paradoxical SUBREG. */ - tmp1 = gen_reg_rtx (SImode); - emit_move_insn (tmp1, gen_lowpart (SImode, val)); - /* Insert the SImode value as low element of V4SImode vector. */ - tmp2 = gen_reg_rtx (V4SImode); - tmp1 = gen_rtx_VEC_MERGE (V4SImode, - gen_rtx_VEC_DUPLICATE (V4SImode, tmp1), - CONST0_RTX (V4SImode), - const1_rtx); - emit_insn (gen_rtx_SET (VOIDmode, tmp2, tmp1)); - /* Cast the V4SImode vector back to a V8HImode vector. */ - tmp1 = gen_reg_rtx (V8HImode); - emit_move_insn (tmp1, gen_lowpart (V8HImode, tmp2)); - /* Duplicate the low short through the whole low SImode word. */ - emit_insn (gen_sse2_punpcklwd (tmp1, tmp1, tmp1)); - /* Cast the V8HImode vector back to a V4SImode vector. */ - tmp2 = gen_reg_rtx (V4SImode); - emit_move_insn (tmp2, gen_lowpart (V4SImode, tmp1)); - /* Replicate the low element of the V4SImode vector. */ - emit_insn (gen_sse2_pshufd (tmp2, tmp2, const0_rtx)); - /* Cast the V2SImode back to V8HImode, and store in target. */ - emit_move_insn (target, gen_lowpart (V8HImode, tmp2)); - return true; - } - smode = HImode; - wsmode = SImode; - wvmode = V4SImode; - goto widen; - case V16QImode: - if (TARGET_SSE2) - { - rtx tmp1, tmp2; - /* Extend QImode to SImode using a paradoxical SUBREG. */ - tmp1 = gen_reg_rtx (SImode); - emit_move_insn (tmp1, gen_lowpart (SImode, val)); - /* Insert the SImode value as low element of V4SImode vector. */ - tmp2 = gen_reg_rtx (V4SImode); - tmp1 = gen_rtx_VEC_MERGE (V4SImode, - gen_rtx_VEC_DUPLICATE (V4SImode, tmp1), - CONST0_RTX (V4SImode), - const1_rtx); - emit_insn (gen_rtx_SET (VOIDmode, tmp2, tmp1)); - /* Cast the V4SImode vector back to a V16QImode vector. */ - tmp1 = gen_reg_rtx (V16QImode); - emit_move_insn (tmp1, gen_lowpart (V16QImode, tmp2)); - /* Duplicate the low byte through the whole low SImode word. */ - emit_insn (gen_sse2_punpcklbw (tmp1, tmp1, tmp1)); - emit_insn (gen_sse2_punpcklbw (tmp1, tmp1, tmp1)); - /* Cast the V16QImode vector back to a V4SImode vector. */ - tmp2 = gen_reg_rtx (V4SImode); - emit_move_insn (tmp2, gen_lowpart (V4SImode, tmp1)); - /* Replicate the low element of the V4SImode vector. */ - emit_insn (gen_sse2_pshufd (tmp2, tmp2, const0_rtx)); - /* Cast the V2SImode back to V16QImode, and store in target. */ - emit_move_insn (target, gen_lowpart (V16QImode, tmp2)); - return true; - } - smode = QImode; - wsmode = HImode; - wvmode = V8HImode; - goto widen; - widen: - /* Replicate the value once into the next wider mode and recurse. */ - val = convert_modes (wsmode, smode, val, true); - x = expand_simple_binop (wsmode, ASHIFT, val, - GEN_INT (GET_MODE_BITSIZE (smode)), - NULL_RTX, 1, OPTAB_LIB_WIDEN); - val = expand_simple_binop (wsmode, IOR, val, x, x, 1, OPTAB_LIB_WIDEN); - - x = gen_reg_rtx (wvmode); - if (!ix86_expand_vector_init_duplicate (mmx_ok, wvmode, x, val)) - gcc_unreachable (); - emit_move_insn (target, gen_lowpart (mode, x)); - return true; - - default: - return false; - } -} - -/* A subroutine of ix86_expand_vector_init. Store into TARGET a vector - whose ONE_VAR element is VAR, and other elements are zero. Return true - if successful. */ - -static bool -ix86_expand_vector_init_one_nonzero (bool mmx_ok, enum machine_mode mode, - rtx target, rtx var, int one_var) -{ - enum machine_mode vsimode; - rtx new_target; - rtx x, tmp; - - switch (mode) - { - case V2SFmode: - case V2SImode: - if (!mmx_ok) - return false; - /* FALLTHRU */ - - case V2DFmode: - case V2DImode: - if (one_var != 0) - return false; - var = force_reg (GET_MODE_INNER (mode), var); - x = gen_rtx_VEC_CONCAT (mode, var, CONST0_RTX (GET_MODE_INNER (mode))); - emit_insn (gen_rtx_SET (VOIDmode, target, x)); - return true; - - case V4SFmode: - case V4SImode: - if (!REG_P (target) || REGNO (target) < FIRST_PSEUDO_REGISTER) - new_target = gen_reg_rtx (mode); - else - new_target = target; - var = force_reg (GET_MODE_INNER (mode), var); - x = gen_rtx_VEC_DUPLICATE (mode, var); - x = gen_rtx_VEC_MERGE (mode, x, CONST0_RTX (mode), const1_rtx); - emit_insn (gen_rtx_SET (VOIDmode, new_target, x)); - if (one_var != 0) - { - /* We need to shuffle the value to the correct position, so - create a new pseudo to store the intermediate result. */ - - /* With SSE2, we can use the integer shuffle insns. */ - if (mode != V4SFmode && TARGET_SSE2) - { - emit_insn (gen_sse2_pshufd_1 (new_target, new_target, - GEN_INT (1), - GEN_INT (one_var == 1 ? 0 : 1), - GEN_INT (one_var == 2 ? 0 : 1), - GEN_INT (one_var == 3 ? 0 : 1))); - if (target != new_target) - emit_move_insn (target, new_target); - return true; - } - - /* Otherwise convert the intermediate result to V4SFmode and - use the SSE1 shuffle instructions. */ - if (mode != V4SFmode) - { - tmp = gen_reg_rtx (V4SFmode); - emit_move_insn (tmp, gen_lowpart (V4SFmode, new_target)); - } - else - tmp = new_target; - - emit_insn (gen_sse_shufps_1 (tmp, tmp, tmp, - GEN_INT (1), - GEN_INT (one_var == 1 ? 0 : 1), - GEN_INT (one_var == 2 ? 0+4 : 1+4), - GEN_INT (one_var == 3 ? 0+4 : 1+4))); - - if (mode != V4SFmode) - emit_move_insn (target, gen_lowpart (V4SImode, tmp)); - else if (tmp != target) - emit_move_insn (target, tmp); - } - else if (target != new_target) - emit_move_insn (target, new_target); - return true; - - case V8HImode: - case V16QImode: - vsimode = V4SImode; - goto widen; - case V4HImode: - case V8QImode: - if (!mmx_ok) - return false; - vsimode = V2SImode; - goto widen; - widen: - if (one_var != 0) - return false; - - /* Zero extend the variable element to SImode and recurse. */ - var = convert_modes (SImode, GET_MODE_INNER (mode), var, true); - - x = gen_reg_rtx (vsimode); - if (!ix86_expand_vector_init_one_nonzero (mmx_ok, vsimode, x, - var, one_var)) - gcc_unreachable (); - - emit_move_insn (target, gen_lowpart (mode, x)); - return true; - - default: - return false; - } -} - -/* A subroutine of ix86_expand_vector_init. Store into TARGET a vector - consisting of the values in VALS. It is known that all elements - except ONE_VAR are constants. Return true if successful. */ -static bool -ix86_expand_vector_init_one_var (bool mmx_ok, enum machine_mode mode, - rtx target, rtx vals, int one_var) +/* Return if we do not know how to pass TYPE solely in registers. */ +bool +ix86_must_pass_in_stack (enum machine_mode mode, tree type) { - rtx var = XVECEXP (vals, 0, one_var); - enum machine_mode wmode; - rtx const_vec, x; - - const_vec = copy_rtx (vals); - XVECEXP (const_vec, 0, one_var) = CONST0_RTX (GET_MODE_INNER (mode)); - const_vec = gen_rtx_CONST_VECTOR (mode, XVEC (const_vec, 0)); - - switch (mode) - { - case V2DFmode: - case V2DImode: - case V2SFmode: - case V2SImode: - /* For the two element vectors, it's just as easy to use - the general case. */ - return false; - - case V4SFmode: - case V4SImode: - case V8HImode: - case V4HImode: - break; - - case V16QImode: - wmode = V8HImode; - goto widen; - case V8QImode: - wmode = V4HImode; - goto widen; - widen: - /* There's no way to set one QImode entry easily. Combine - the variable value with its adjacent constant value, and - promote to an HImode set. */ - x = XVECEXP (vals, 0, one_var ^ 1); - if (one_var & 1) - { - var = convert_modes (HImode, QImode, var, true); - var = expand_simple_binop (HImode, ASHIFT, var, GEN_INT (8), - NULL_RTX, 1, OPTAB_LIB_WIDEN); - x = GEN_INT (INTVAL (x) & 0xff); - } - else - { - var = convert_modes (HImode, QImode, var, true); - x = gen_int_mode (INTVAL (x) << 8, HImode); - } - if (x != const0_rtx) - var = expand_simple_binop (HImode, IOR, var, x, var, - 1, OPTAB_LIB_WIDEN); - - x = gen_reg_rtx (wmode); - emit_move_insn (x, gen_lowpart (wmode, const_vec)); - ix86_expand_vector_set (mmx_ok, x, var, one_var >> 1); - - emit_move_insn (target, gen_lowpart (mode, x)); - return true; - - default: - return false; - } - - emit_move_insn (target, const_vec); - ix86_expand_vector_set (mmx_ok, target, var, one_var); - return true; + if (default_must_pass_in_stack (mode, type)) + return true; + return (!TARGET_64BIT && type && mode == TImode); } -/* A subroutine of ix86_expand_vector_init. Handle the most general case: - all values variable, and none identical. */ - -static void -ix86_expand_vector_init_general (bool mmx_ok, enum machine_mode mode, - rtx target, rtx vals) -{ - enum machine_mode half_mode = GET_MODE_INNER (mode); - rtx op0 = NULL, op1 = NULL; - bool use_vec_concat = false; - - switch (mode) - { - case V2SFmode: - case V2SImode: - if (!mmx_ok && !TARGET_SSE) - break; - /* FALLTHRU */ - - case V2DFmode: - case V2DImode: - /* For the two element vectors, we always implement VEC_CONCAT. */ - op0 = XVECEXP (vals, 0, 0); - op1 = XVECEXP (vals, 0, 1); - use_vec_concat = true; - break; - - case V4SFmode: - half_mode = V2SFmode; - goto half; - case V4SImode: - half_mode = V2SImode; - goto half; - half: - { - rtvec v; - - /* For V4SF and V4SI, we implement a concat of two V2 vectors. - Recurse to load the two halves. */ - - op0 = gen_reg_rtx (half_mode); - v = gen_rtvec (2, XVECEXP (vals, 0, 0), XVECEXP (vals, 0, 1)); - ix86_expand_vector_init (false, op0, gen_rtx_PARALLEL (half_mode, v)); - - op1 = gen_reg_rtx (half_mode); - v = gen_rtvec (2, XVECEXP (vals, 0, 2), XVECEXP (vals, 0, 3)); - ix86_expand_vector_init (false, op1, gen_rtx_PARALLEL (half_mode, v)); - - use_vec_concat = true; - } - break; - - case V8HImode: - case V16QImode: - case V4HImode: - case V8QImode: - break; - - default: - gcc_unreachable (); - } - - if (use_vec_concat) - { - if (!register_operand (op0, half_mode)) - op0 = force_reg (half_mode, op0); - if (!register_operand (op1, half_mode)) - op1 = force_reg (half_mode, op1); - - emit_insn (gen_rtx_SET (VOIDmode, target, - gen_rtx_VEC_CONCAT (mode, op0, op1))); - } - else - { - int i, j, n_elts, n_words, n_elt_per_word; - enum machine_mode inner_mode; - rtx words[4], shift; - - inner_mode = GET_MODE_INNER (mode); - n_elts = GET_MODE_NUNITS (mode); - n_words = GET_MODE_SIZE (mode) / UNITS_PER_WORD; - n_elt_per_word = n_elts / n_words; - shift = GEN_INT (GET_MODE_BITSIZE (inner_mode)); - - for (i = 0; i < n_words; ++i) - { - rtx word = NULL_RTX; - - for (j = 0; j < n_elt_per_word; ++j) - { - rtx elt = XVECEXP (vals, 0, (i+1)*n_elt_per_word - j - 1); - elt = convert_modes (word_mode, inner_mode, elt, true); - - if (j == 0) - word = elt; - else - { - word = expand_simple_binop (word_mode, ASHIFT, word, shift, - word, 1, OPTAB_LIB_WIDEN); - word = expand_simple_binop (word_mode, IOR, word, elt, - word, 1, OPTAB_LIB_WIDEN); - } - } - - words[i] = word; - } - - if (n_words == 1) - emit_move_insn (target, gen_lowpart (mode, words[0])); - else if (n_words == 2) - { - rtx tmp = gen_reg_rtx (mode); - emit_insn (gen_rtx_CLOBBER (VOIDmode, tmp)); - emit_move_insn (gen_lowpart (word_mode, tmp), words[0]); - emit_move_insn (gen_highpart (word_mode, tmp), words[1]); - emit_move_insn (target, tmp); - } - else if (n_words == 4) - { - rtx tmp = gen_reg_rtx (V4SImode); - vals = gen_rtx_PARALLEL (V4SImode, gen_rtvec_v (4, words)); - ix86_expand_vector_init_general (false, V4SImode, tmp, vals); - emit_move_insn (target, gen_lowpart (mode, tmp)); - } - else - gcc_unreachable (); - } -} - -/* Initialize vector TARGET via VALS. Suppress the use of MMX - instructions unless MMX_OK is true. */ - +/* Initialize vector TARGET via VALS. */ void -ix86_expand_vector_init (bool mmx_ok, rtx target, rtx vals) +ix86_expand_vector_init (rtx target, rtx vals) { enum machine_mode mode = GET_MODE (target); - enum machine_mode inner_mode = GET_MODE_INNER (mode); - int n_elts = GET_MODE_NUNITS (mode); - int n_var = 0, one_var = -1; - bool all_same = true, all_const_zero = true; + int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode)); + int n_elts = (GET_MODE_SIZE (mode) / elt_size); int i; - rtx x; - - for (i = 0; i < n_elts; ++i) - { - x = XVECEXP (vals, 0, i); - if (!CONSTANT_P (x)) - n_var++, one_var = i; - else if (x != CONST0_RTX (inner_mode)) - all_const_zero = false; - if (i > 0 && !rtx_equal_p (x, XVECEXP (vals, 0, 0))) - all_same = false; - } + + for (i = n_elts - 1; i >= 0; i--) + if (GET_CODE (XVECEXP (vals, 0, i)) != CONST_INT + && GET_CODE (XVECEXP (vals, 0, i)) != CONST_DOUBLE) + break; - /* Constants are best loaded from the constant pool. */ - if (n_var == 0) + /* Few special cases first... + ... constants are best loaded from constant pool. */ + if (i < 0) { emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0))); return; } - /* If all values are identical, broadcast the value. */ - if (all_same - && ix86_expand_vector_init_duplicate (mmx_ok, mode, target, - XVECEXP (vals, 0, 0))) - return; - - /* Values where only one field is non-constant are best loaded from - the pool and overwritten via move later. */ - if (n_var == 1) - { - if (all_const_zero - && ix86_expand_vector_init_one_nonzero (mmx_ok, mode, target, - XVECEXP (vals, 0, one_var), - one_var)) - return; - - if (ix86_expand_vector_init_one_var (mmx_ok, mode, target, vals, one_var)) - return; - } - - ix86_expand_vector_init_general (mmx_ok, mode, target, vals); -} - -void -ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt) -{ - enum machine_mode mode = GET_MODE (target); - enum machine_mode inner_mode = GET_MODE_INNER (mode); - bool use_vec_merge = false; - rtx tmp; - - switch (mode) + /* ... values where only first field is non-constant are best loaded + from the pool and overwriten via move later. */ + if (!i) { - case V2SFmode: - case V2SImode: - if (mmx_ok) - { - tmp = gen_reg_rtx (GET_MODE_INNER (mode)); - ix86_expand_vector_extract (true, tmp, target, 1 - elt); - if (elt == 0) - tmp = gen_rtx_VEC_CONCAT (mode, tmp, val); - else - tmp = gen_rtx_VEC_CONCAT (mode, val, tmp); - emit_insn (gen_rtx_SET (VOIDmode, target, tmp)); - return; - } - break; - - case V2DFmode: - case V2DImode: - { - rtx op0, op1; - - /* For the two element vectors, we implement a VEC_CONCAT with - the extraction of the other element. */ - - tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, GEN_INT (1 - elt))); - tmp = gen_rtx_VEC_SELECT (inner_mode, target, tmp); - - if (elt == 0) - op0 = val, op1 = tmp; - else - op0 = tmp, op1 = val; - - tmp = gen_rtx_VEC_CONCAT (mode, op0, op1); - emit_insn (gen_rtx_SET (VOIDmode, target, tmp)); - } - return; - - case V4SFmode: - switch (elt) - { - case 0: - use_vec_merge = true; - break; - - case 1: - /* tmp = target = A B C D */ - tmp = copy_to_reg (target); - /* target = A A B B */ - emit_insn (gen_sse_unpcklps (target, target, target)); - /* target = X A B B */ - ix86_expand_vector_set (false, target, val, 0); - /* target = A X C D */ - emit_insn (gen_sse_shufps_1 (target, target, tmp, - GEN_INT (1), GEN_INT (0), - GEN_INT (2+4), GEN_INT (3+4))); - return; - - case 2: - /* tmp = target = A B C D */ - tmp = copy_to_reg (target); - /* tmp = X B C D */ - ix86_expand_vector_set (false, tmp, val, 0); - /* target = A B X D */ - emit_insn (gen_sse_shufps_1 (target, target, tmp, - GEN_INT (0), GEN_INT (1), - GEN_INT (0+4), GEN_INT (3+4))); - return; - - case 3: - /* tmp = target = A B C D */ - tmp = copy_to_reg (target); - /* tmp = X B C D */ - ix86_expand_vector_set (false, tmp, val, 0); - /* target = A B X D */ - emit_insn (gen_sse_shufps_1 (target, target, tmp, - GEN_INT (0), GEN_INT (1), - GEN_INT (2+4), GEN_INT (0+4))); - return; - - default: - gcc_unreachable (); - } - break; + rtx op = simplify_gen_subreg (mode, XVECEXP (vals, 0, 0), + GET_MODE_INNER (mode), 0); - case V4SImode: - /* Element 0 handled by vec_merge below. */ - if (elt == 0) - { - use_vec_merge = true; - break; - } - - if (TARGET_SSE2) - { - /* With SSE2, use integer shuffles to swap element 0 and ELT, - store into element 0, then shuffle them back. */ - - rtx order[4]; - - order[0] = GEN_INT (elt); - order[1] = const1_rtx; - order[2] = const2_rtx; - order[3] = GEN_INT (3); - order[elt] = const0_rtx; - - emit_insn (gen_sse2_pshufd_1 (target, target, order[0], - order[1], order[2], order[3])); - - ix86_expand_vector_set (false, target, val, 0); - - emit_insn (gen_sse2_pshufd_1 (target, target, order[0], - order[1], order[2], order[3])); - } - else + op = force_reg (mode, op); + XVECEXP (vals, 0, 0) = CONST0_RTX (GET_MODE_INNER (mode)); + emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0))); + switch (GET_MODE (target)) { - /* For SSE1, we have to reuse the V4SF code. */ - ix86_expand_vector_set (false, gen_lowpart (V4SFmode, target), - gen_lowpart (SFmode, val), elt); + case V2DFmode: + emit_insn (gen_sse2_movsd (target, target, op)); + break; + case V4SFmode: + emit_insn (gen_sse_movss (target, target, op)); + break; + default: + break; } return; - - case V8HImode: - use_vec_merge = TARGET_SSE2; - break; - case V4HImode: - use_vec_merge = mmx_ok && (TARGET_SSE || TARGET_3DNOW_A); - break; - - case V16QImode: - case V8QImode: - default: - break; } - if (use_vec_merge) - { - tmp = gen_rtx_VEC_DUPLICATE (mode, val); - tmp = gen_rtx_VEC_MERGE (mode, tmp, target, GEN_INT (1 << elt)); - emit_insn (gen_rtx_SET (VOIDmode, target, tmp)); - } - else - { - rtx mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), false); - - emit_move_insn (mem, target); - - tmp = adjust_address (mem, inner_mode, elt*GET_MODE_SIZE (inner_mode)); - emit_move_insn (tmp, val); - - emit_move_insn (target, mem); - } -} - -void -ix86_expand_vector_extract (bool mmx_ok, rtx target, rtx vec, int elt) -{ - enum machine_mode mode = GET_MODE (vec); - enum machine_mode inner_mode = GET_MODE_INNER (mode); - bool use_vec_extr = false; - rtx tmp; - - switch (mode) + /* And the busy sequence doing rotations. */ + switch (GET_MODE (target)) { - case V2SImode: - case V2SFmode: - if (!mmx_ok) - break; - /* FALLTHRU */ - - case V2DFmode: - case V2DImode: - use_vec_extr = true; - break; - - case V4SFmode: - switch (elt) - { - case 0: - tmp = vec; - break; - - case 1: - case 3: - tmp = gen_reg_rtx (mode); - emit_insn (gen_sse_shufps_1 (tmp, vec, vec, - GEN_INT (elt), GEN_INT (elt), - GEN_INT (elt+4), GEN_INT (elt+4))); - break; - - case 2: - tmp = gen_reg_rtx (mode); - emit_insn (gen_sse_unpckhps (tmp, vec, vec)); - break; - - default: - gcc_unreachable (); - } - vec = tmp; - use_vec_extr = true; - elt = 0; - break; - - case V4SImode: - if (TARGET_SSE2) + case V2DFmode: { - switch (elt) - { - case 0: - tmp = vec; - break; + rtx vecop0 = + simplify_gen_subreg (V2DFmode, XVECEXP (vals, 0, 0), DFmode, 0); + rtx vecop1 = + simplify_gen_subreg (V2DFmode, XVECEXP (vals, 0, 1), DFmode, 0); - case 1: - case 3: - tmp = gen_reg_rtx (mode); - emit_insn (gen_sse2_pshufd_1 (tmp, vec, - GEN_INT (elt), GEN_INT (elt), - GEN_INT (elt), GEN_INT (elt))); - break; - - case 2: - tmp = gen_reg_rtx (mode); - emit_insn (gen_sse2_punpckhdq (tmp, vec, vec)); - break; - - default: - gcc_unreachable (); - } - vec = tmp; - use_vec_extr = true; - elt = 0; - } - else - { - /* For SSE1, we have to reuse the V4SF code. */ - ix86_expand_vector_extract (false, gen_lowpart (SFmode, target), - gen_lowpart (V4SFmode, vec), elt); - return; + vecop0 = force_reg (V2DFmode, vecop0); + vecop1 = force_reg (V2DFmode, vecop1); + emit_insn (gen_sse2_unpcklpd (target, vecop0, vecop1)); } - break; - - case V8HImode: - use_vec_extr = TARGET_SSE2; - break; - case V4HImode: - use_vec_extr = mmx_ok && (TARGET_SSE || TARGET_3DNOW_A); - break; - - case V16QImode: - case V8QImode: - /* ??? Could extract the appropriate HImode element and shift. */ - default: - break; - } - - if (use_vec_extr) - { - tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, GEN_INT (elt))); - tmp = gen_rtx_VEC_SELECT (inner_mode, vec, tmp); - - /* Let the rtl optimizers know about the zero extension performed. */ - if (inner_mode == HImode) + break; + case V4SFmode: { - tmp = gen_rtx_ZERO_EXTEND (SImode, tmp); - target = gen_lowpart (SImode, target); + rtx vecop0 = + simplify_gen_subreg (V4SFmode, XVECEXP (vals, 0, 0), SFmode, 0); + rtx vecop1 = + simplify_gen_subreg (V4SFmode, XVECEXP (vals, 0, 1), SFmode, 0); + rtx vecop2 = + simplify_gen_subreg (V4SFmode, XVECEXP (vals, 0, 2), SFmode, 0); + rtx vecop3 = + simplify_gen_subreg (V4SFmode, XVECEXP (vals, 0, 3), SFmode, 0); + rtx tmp1 = gen_reg_rtx (V4SFmode); + rtx tmp2 = gen_reg_rtx (V4SFmode); + + vecop0 = force_reg (V4SFmode, vecop0); + vecop1 = force_reg (V4SFmode, vecop1); + vecop2 = force_reg (V4SFmode, vecop2); + vecop3 = force_reg (V4SFmode, vecop3); + emit_insn (gen_sse_unpcklps (tmp1, vecop1, vecop3)); + emit_insn (gen_sse_unpcklps (tmp2, vecop0, vecop2)); + emit_insn (gen_sse_unpcklps (target, tmp2, tmp1)); } - - emit_insn (gen_rtx_SET (VOIDmode, target, tmp)); - } - else - { - rtx mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), false); - - emit_move_insn (mem, vec); - - tmp = adjust_address (mem, inner_mode, elt*GET_MODE_SIZE (inner_mode)); - emit_move_insn (target, tmp); - } -} - -/* Expand a vector reduction on V4SFmode for SSE1. FN is the binary - pattern to reduce; DEST is the destination; IN is the input vector. */ - -void -ix86_expand_reduc_v4sf (rtx (*fn) (rtx, rtx, rtx), rtx dest, rtx in) -{ - rtx tmp1, tmp2, tmp3; - - tmp1 = gen_reg_rtx (V4SFmode); - tmp2 = gen_reg_rtx (V4SFmode); - tmp3 = gen_reg_rtx (V4SFmode); - - emit_insn (gen_sse_movhlps (tmp1, in, in)); - emit_insn (fn (tmp2, tmp1, in)); - - emit_insn (gen_sse_shufps_1 (tmp3, tmp2, tmp2, - GEN_INT (1), GEN_INT (1), - GEN_INT (1+4), GEN_INT (1+4))); - emit_insn (fn (dest, tmp2, tmp3)); -} - -/* Target hook for scalar_mode_supported_p. */ -static bool -ix86_scalar_mode_supported_p (enum machine_mode mode) -{ - if (DECIMAL_FLOAT_MODE_P (mode)) - return true; - else - return default_scalar_mode_supported_p (mode); -} - -/* Implements target hook vector_mode_supported_p. */ -static bool -ix86_vector_mode_supported_p (enum machine_mode mode) -{ - if (TARGET_SSE && VALID_SSE_REG_MODE (mode)) - return true; - if (TARGET_SSE2 && VALID_SSE2_REG_MODE (mode)) - return true; - if (TARGET_MMX && VALID_MMX_REG_MODE (mode)) - return true; - if (TARGET_3DNOW && VALID_MMX_REG_MODE_3DNOW (mode)) - return true; - return false; -} - -/* Worker function for TARGET_MD_ASM_CLOBBERS. - - We do this in the new i386 backend to maintain source compatibility - with the old cc0-based compiler. */ - -static tree -ix86_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED, - tree inputs ATTRIBUTE_UNUSED, - tree clobbers) -{ - clobbers = tree_cons (NULL_TREE, build_string (5, "flags"), - clobbers); - clobbers = tree_cons (NULL_TREE, build_string (4, "fpsr"), - clobbers); - clobbers = tree_cons (NULL_TREE, build_string (7, "dirflag"), - clobbers); - return clobbers; -} - -/* Return true if this goes in small data/bss. */ - -static bool -ix86_in_large_data_p (tree exp) -{ - if (ix86_cmodel != CM_MEDIUM && ix86_cmodel != CM_MEDIUM_PIC) - return false; - - /* Functions are never large data. */ - if (TREE_CODE (exp) == FUNCTION_DECL) - return false; - - if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) - { - const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); - if (strcmp (section, ".ldata") == 0 - || strcmp (section, ".lbss") == 0) - return true; - return false; - } - else - { - HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); - - /* If this is an incomplete type with size 0, then we can't put it - in data because it might be too big when completed. */ - if (!size || size > ix86_section_threshold) - return true; - } - - return false; -} -static void -ix86_encode_section_info (tree decl, rtx rtl, int first) -{ - default_encode_section_info (decl, rtl, first); - - if (TREE_CODE (decl) == VAR_DECL - && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)) - && ix86_in_large_data_p (decl)) - SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_FAR_ADDR; -} - -/* Worker function for REVERSE_CONDITION. */ - -enum rtx_code -ix86_reverse_condition (enum rtx_code code, enum machine_mode mode) -{ - return (mode != CCFPmode && mode != CCFPUmode - ? reverse_condition (code) - : reverse_condition_maybe_unordered (code)); -} - -/* Output code to perform an x87 FP register move, from OPERANDS[1] - to OPERANDS[0]. */ - -const char * -output_387_reg_move (rtx insn, rtx *operands) -{ - if (REG_P (operands[1]) - && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) - { - if (REGNO (operands[0]) == FIRST_STACK_REG) - return output_387_ffreep (operands, 0); - return "fstp\t%y0"; - } - if (STACK_TOP_P (operands[0])) - return "fld%z1\t%y1"; - return "fst\t%y0"; -} - -/* Output code to perform a conditional jump to LABEL, if C2 flag in - FP status register is set. */ - -void -ix86_emit_fp_unordered_jump (rtx label) -{ - rtx reg = gen_reg_rtx (HImode); - rtx temp; - - emit_insn (gen_x86_fnstsw_1 (reg)); - - if (TARGET_USE_SAHF) - { - emit_insn (gen_x86_sahf_1 (reg)); - - temp = gen_rtx_REG (CCmode, FLAGS_REG); - temp = gen_rtx_UNORDERED (VOIDmode, temp, const0_rtx); - } - else - { - emit_insn (gen_testqi_ext_ccno_0 (reg, GEN_INT (0x04))); - - temp = gen_rtx_REG (CCNOmode, FLAGS_REG); - temp = gen_rtx_NE (VOIDmode, temp, const0_rtx); - } - - temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp, - gen_rtx_LABEL_REF (VOIDmode, label), - pc_rtx); - temp = gen_rtx_SET (VOIDmode, pc_rtx, temp); - emit_jump_insn (temp); -} - -/* Output code to perform a log1p XFmode calculation. */ - -void ix86_emit_i387_log1p (rtx op0, rtx op1) -{ - rtx label1 = gen_label_rtx (); - rtx label2 = gen_label_rtx (); - - rtx tmp = gen_reg_rtx (XFmode); - rtx tmp2 = gen_reg_rtx (XFmode); - - emit_insn (gen_absxf2 (tmp, op1)); - emit_insn (gen_cmpxf (tmp, - CONST_DOUBLE_FROM_REAL_VALUE ( - REAL_VALUE_ATOF ("0.29289321881345247561810596348408353", XFmode), - XFmode))); - emit_jump_insn (gen_bge (label1)); - - emit_move_insn (tmp2, standard_80387_constant_rtx (4)); /* fldln2 */ - emit_insn (gen_fyl2xp1_xf3 (op0, tmp2, op1)); - emit_jump (label2); - - emit_label (label1); - emit_move_insn (tmp, CONST1_RTX (XFmode)); - emit_insn (gen_addxf3 (tmp, op1, tmp)); - emit_move_insn (tmp2, standard_80387_constant_rtx (4)); /* fldln2 */ - emit_insn (gen_fyl2x_xf3 (op0, tmp2, tmp)); - - emit_label (label2); -} - -/* Solaris implementation of TARGET_ASM_NAMED_SECTION. */ - -static void -i386_solaris_elf_named_section (const char *name, unsigned int flags, - tree decl) -{ - /* With Binutils 2.15, the "@unwind" marker must be specified on - every occurrence of the ".eh_frame" section, not just the first - one. */ - if (TARGET_64BIT - && strcmp (name, ".eh_frame") == 0) - { - fprintf (asm_out_file, "\t.section\t%s,\"%s\",@unwind\n", name, - flags & SECTION_WRITE ? "aw" : "a"); - return; - } - default_elf_asm_named_section (name, flags, decl); -} - -/* Return the mangling of TYPE if it is an extended fundamental type. */ - -static const char * -ix86_mangle_fundamental_type (tree type) -{ - switch (TYPE_MODE (type)) - { - case TFmode: - /* __float128 is "g". */ - return "g"; - case XFmode: - /* "long double" or __float80 is "e". */ - return "e"; - default: - return NULL; + break; + default: + abort (); } } -/* For 32-bit code we can save PIC register setup by using - __stack_chk_fail_local hidden function instead of calling - __stack_chk_fail directly. 64-bit code doesn't need to setup any PIC - register, so it is better to call __stack_chk_fail directly. */ - -static tree -ix86_stack_protect_fail (void) -{ - return TARGET_64BIT - ? default_external_stack_protect_fail () - : default_hidden_stack_protect_fail (); -} - -/* Select a format to encode pointers in exception handling data. CODE - is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is - true if the symbol may be affected by dynamic relocations. - - ??? All x86 object file formats are capable of representing this. - After all, the relocation needed is the same as for the call insn. - Whether or not a particular assembler allows us to enter such, I - guess we'll have to see. */ -int -asm_preferred_eh_data_format (int code, int global) -{ - if (flag_pic) - { - int type = DW_EH_PE_sdata8; - if (!TARGET_64BIT - || ix86_cmodel == CM_SMALL_PIC - || (ix86_cmodel == CM_MEDIUM_PIC && (global || code))) - type = DW_EH_PE_sdata4; - return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type; - } - if (ix86_cmodel == CM_SMALL - || (ix86_cmodel == CM_MEDIUM && code)) - return DW_EH_PE_udata4; - return DW_EH_PE_absptr; -} - #include "gt-i386.h" diff --git a/contrib/gcc/config/i386/i386.h b/contrib/gcc/config/i386/i386.h index ba732dc..6afc3ac 100644 --- a/contrib/gcc/config/i386/i386.h +++ b/contrib/gcc/config/i386/i386.h @@ -1,6 +1,6 @@ /* Definitions of target machine for GCC for IA-32. Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* The purpose of this file is to define the characteristics of the i386, independent of assembler syntax or operating system. @@ -41,10 +41,10 @@ struct processor_costs { const int lea; /* cost of a lea instruction */ const int shift_var; /* variable shift costs */ const int shift_const; /* constant shift costs */ - const int mult_init[5]; /* cost of starting a multiply + const int mult_init[5]; /* cost of starting a multiply in QImode, HImode, SImode, DImode, TImode*/ const int mult_bit; /* cost of multiply per each bit set */ - const int divide[5]; /* cost of a divide/mod + const int divide[5]; /* cost of a divide/mod in QImode, HImode, SImode, DImode, TImode*/ int movsx; /* The cost of movsx operation. */ int movzx; /* The cost of movzx operation. */ @@ -88,33 +88,118 @@ struct processor_costs { extern const struct processor_costs *ix86_cost; +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + /* Macros used in the machine description to test the flags. */ /* configure can arrange to make this 2, to force a 486. */ #ifndef TARGET_CPU_DEFAULT -#define TARGET_CPU_DEFAULT TARGET_CPU_DEFAULT_generic +#ifdef TARGET_64BIT_DEFAULT +#define TARGET_CPU_DEFAULT TARGET_CPU_DEFAULT_k8 +#else +#define TARGET_CPU_DEFAULT 0 #endif - -#ifndef TARGET_FPMATH_DEFAULT -#define TARGET_FPMATH_DEFAULT \ - (TARGET_64BIT && TARGET_SSE ? FPMATH_SSE : FPMATH_387) #endif -#define TARGET_FLOAT_RETURNS_IN_80387 TARGET_FLOAT_RETURNS +/* Masks for the -m switches */ +#define MASK_80387 0x00000001 /* Hardware floating point */ +#define MASK_RTD 0x00000002 /* Use ret that pops args */ +#define MASK_ALIGN_DOUBLE 0x00000004 /* align doubles to 2 word boundary */ +#define MASK_SVR3_SHLIB 0x00000008 /* Uninit locals into bss */ +#define MASK_IEEE_FP 0x00000010 /* IEEE fp comparisons */ +#define MASK_FLOAT_RETURNS 0x00000020 /* Return float in st(0) */ +#define MASK_NO_FANCY_MATH_387 0x00000040 /* Disable sin, cos, sqrt */ +#define MASK_OMIT_LEAF_FRAME_POINTER 0x080 /* omit leaf frame pointers */ +#define MASK_STACK_PROBE 0x00000100 /* Enable stack probing */ +#define MASK_NO_ALIGN_STROPS 0x00000200 /* Enable aligning of string ops. */ +#define MASK_INLINE_ALL_STROPS 0x00000400 /* Inline stringops in all cases */ +#define MASK_NO_PUSH_ARGS 0x00000800 /* Use push instructions */ +#define MASK_ACCUMULATE_OUTGOING_ARGS 0x00001000/* Accumulate outgoing args */ +#define MASK_MMX 0x00002000 /* Support MMX regs/builtins */ +#define MASK_SSE 0x00004000 /* Support SSE regs/builtins */ +#define MASK_SSE2 0x00008000 /* Support SSE2 regs/builtins */ +#define MASK_SSE3 0x00010000 /* Support SSE3 regs/builtins */ +#define MASK_3DNOW 0x00020000 /* Support 3Dnow builtins */ +#define MASK_3DNOW_A 0x00040000 /* Support Athlon 3Dnow builtins */ +#define MASK_128BIT_LONG_DOUBLE 0x00080000 /* long double size is 128bit */ +#define MASK_64BIT 0x00100000 /* Produce 64bit code */ +#define MASK_MS_BITFIELD_LAYOUT 0x00200000 /* Use native (MS) bitfield layout */ +#define MASK_TLS_DIRECT_SEG_REFS 0x00400000 /* Avoid adding %gs:0 */ + +/* Unused: 0x03e0000 */ + +/* ... overlap with subtarget options starts by 0x04000000. */ +#define MASK_NO_RED_ZONE 0x04000000 /* Do not use red zone */ +#define MASK_NO_ALIGN_LONG_STRINGS 0x08000000 /* Do not align long strings specially */ + +/* Use the floating point instructions */ +#define TARGET_80387 (target_flags & MASK_80387) + +/* Compile using ret insn that pops args. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. */ +#define TARGET_RTD (target_flags & MASK_RTD) + +/* Align doubles to a two word boundary. This breaks compatibility with + the published ABI's for structures containing doubles, but produces + faster code on the pentium. */ +#define TARGET_ALIGN_DOUBLE (target_flags & MASK_ALIGN_DOUBLE) + +/* Use push instructions to save outgoing args. */ +#define TARGET_PUSH_ARGS (!(target_flags & MASK_NO_PUSH_ARGS)) + +/* Accumulate stack adjustments to prologue/epilogue. */ +#define TARGET_ACCUMULATE_OUTGOING_ARGS \ + (target_flags & MASK_ACCUMULATE_OUTGOING_ARGS) + +/* Put uninitialized locals into bss, not data. + Meaningful only on svr3. */ +#define TARGET_SVR3_SHLIB (target_flags & MASK_SVR3_SHLIB) + +/* Use IEEE floating point comparisons. These handle correctly the cases + where the result of a comparison is unordered. Normally SIGFPE is + generated in such cases, in which case this isn't needed. */ +#define TARGET_IEEE_FP (target_flags & MASK_IEEE_FP) + +/* Functions that return a floating point value may return that value + in the 387 FPU or in 386 integer registers. If set, this flag causes + the 387 to be used, which is compatible with most calling conventions. */ +#define TARGET_FLOAT_RETURNS_IN_80387 (target_flags & MASK_FLOAT_RETURNS) + +/* Long double is 128bit instead of 96bit, even when only 80bits are used. + This mode wastes cache, but avoid misaligned data accesses and simplifies + address calculations. */ +#define TARGET_128BIT_LONG_DOUBLE (target_flags & MASK_128BIT_LONG_DOUBLE) + +/* Disable generation of FP sin, cos and sqrt operations for 387. + This is because FreeBSD lacks these in the math-emulator-code */ +#define TARGET_NO_FANCY_MATH_387 (target_flags & MASK_NO_FANCY_MATH_387) + +/* Don't create frame pointers for leaf functions */ +#define TARGET_OMIT_LEAF_FRAME_POINTER \ + (target_flags & MASK_OMIT_LEAF_FRAME_POINTER) + +/* Debug GO_IF_LEGITIMATE_ADDRESS */ +#define TARGET_DEBUG_ADDR (ix86_debug_addr_string != 0) + +/* Debug FUNCTION_ARG macros */ +#define TARGET_DEBUG_ARG (ix86_debug_arg_string != 0) /* 64bit Sledgehammer mode. For libgcc2 we make sure this is a compile-time constant. */ #ifdef IN_LIBGCC2 -#undef TARGET_64BIT #ifdef __x86_64__ #define TARGET_64BIT 1 #else #define TARGET_64BIT 0 #endif #else -#ifndef TARGET_BI_ARCH -#undef TARGET_64BIT +#ifdef TARGET_BI_ARCH +#define TARGET_64BIT (target_flags & MASK_64BIT) +#else #if TARGET_64BIT_DEFAULT #define TARGET_64BIT 1 #else @@ -123,8 +208,8 @@ extern const struct processor_costs *ix86_cost; #endif #endif -#define HAS_LONG_COND_BRANCH 1 -#define HAS_LONG_UNCOND_BRANCH 1 +/* Avoid adding %gs:0 in TLS references; use %gs:address directly. */ +#define TARGET_TLS_DIRECT_SEG_REFS (target_flags & MASK_TLS_DIRECT_SEG_REFS) #define TARGET_386 (ix86_tune == PROCESSOR_I386) #define TARGET_486 (ix86_tune == PROCESSOR_I486) @@ -135,18 +220,14 @@ extern const struct processor_costs *ix86_cost; #define TARGET_PENTIUM4 (ix86_tune == PROCESSOR_PENTIUM4) #define TARGET_K8 (ix86_tune == PROCESSOR_K8) #define TARGET_ATHLON_K8 (TARGET_K8 || TARGET_ATHLON) -#define TARGET_NOCONA (ix86_tune == PROCESSOR_NOCONA) -#define TARGET_GENERIC32 (ix86_tune == PROCESSOR_GENERIC32) -#define TARGET_GENERIC64 (ix86_tune == PROCESSOR_GENERIC64) -#define TARGET_GENERIC (TARGET_GENERIC32 || TARGET_GENERIC64) #define TUNEMASK (1 << ix86_tune) extern const int x86_use_leave, x86_push_memory, x86_zero_extend_with_and; extern const int x86_use_bit_test, x86_cmove, x86_deep_branch; extern const int x86_branch_hints, x86_unroll_strlen; extern const int x86_double_with_add, x86_partial_reg_stall, x86_movx; -extern const int x86_use_himode_fiop, x86_use_simode_fiop; -extern const int x86_use_mov0, x86_use_cltd, x86_read_modify_write; +extern const int x86_use_loop, x86_use_fiop, x86_use_mov0; +extern const int x86_use_cltd, x86_read_modify_write; extern const int x86_read_modify, x86_split_long_moves; extern const int x86_promote_QImode, x86_single_stringop, x86_fast_prefix; extern const int x86_himode_math, x86_qimode_math, x86_promote_qi_regs; @@ -156,15 +237,10 @@ extern const int x86_partial_reg_dependency, x86_memory_mismatch_stall; extern const int x86_accumulate_outgoing_args, x86_prologue_using_move; extern const int x86_epilogue_using_move, x86_decompose_lea; extern const int x86_arch_always_fancy_math_387, x86_shift1; -extern const int x86_sse_partial_reg_dependency, x86_sse_split_regs; +extern const int x86_sse_partial_reg_dependency, x86_sse_partial_regs; extern const int x86_sse_typeless_stores, x86_sse_load0_by_pxor; -extern const int x86_use_ffreep; -extern const int x86_inter_unit_moves, x86_schedule; -extern const int x86_use_bt; -extern const int x86_cmpxchg, x86_cmpxchg8b, x86_cmpxchg16b, x86_xadd; -extern const int x86_use_incdec; -extern const int x86_pad_returns; -extern const int x86_partial_flag_reg_stall; +extern const int x86_use_ffreep, x86_sse_partial_regs_for_cvtsd2ss; +extern const int x86_inter_unit_moves; extern int x86_prefetch_sse; #define TARGET_USE_LEAVE (x86_use_leave & TUNEMASK) @@ -175,16 +251,14 @@ extern int x86_prefetch_sse; /* For sane SSE instruction set generation we need fcomi instruction. It is safe to enable all CMOVE instructions. */ #define TARGET_CMOVE ((x86_cmove & (1 << ix86_arch)) || TARGET_SSE) -#define TARGET_FISTTP (TARGET_SSE3 && TARGET_80387) #define TARGET_DEEP_BRANCH_PREDICTION (x86_deep_branch & TUNEMASK) #define TARGET_BRANCH_PREDICTION_HINTS (x86_branch_hints & TUNEMASK) #define TARGET_DOUBLE_WITH_ADD (x86_double_with_add & TUNEMASK) #define TARGET_USE_SAHF ((x86_use_sahf & TUNEMASK) && !TARGET_64BIT) #define TARGET_MOVX (x86_movx & TUNEMASK) #define TARGET_PARTIAL_REG_STALL (x86_partial_reg_stall & TUNEMASK) -#define TARGET_PARTIAL_FLAG_REG_STALL (x86_partial_flag_reg_stall & TUNEMASK) -#define TARGET_USE_HIMODE_FIOP (x86_use_himode_fiop & TUNEMASK) -#define TARGET_USE_SIMODE_FIOP (x86_use_simode_fiop & TUNEMASK) +#define TARGET_USE_LOOP (x86_use_loop & TUNEMASK) +#define TARGET_USE_FIOP (x86_use_fiop & TUNEMASK) #define TARGET_USE_MOV0 (x86_use_mov0 & TUNEMASK) #define TARGET_USE_CLTD (x86_use_cltd & TUNEMASK) #define TARGET_SPLIT_LONG_MOVES (x86_split_long_moves & TUNEMASK) @@ -205,38 +279,163 @@ extern int x86_prefetch_sse; #define TARGET_PARTIAL_REG_DEPENDENCY (x86_partial_reg_dependency & TUNEMASK) #define TARGET_SSE_PARTIAL_REG_DEPENDENCY \ (x86_sse_partial_reg_dependency & TUNEMASK) -#define TARGET_SSE_SPLIT_REGS (x86_sse_split_regs & TUNEMASK) +#define TARGET_SSE_PARTIAL_REGS (x86_sse_partial_regs & TUNEMASK) +#define TARGET_SSE_PARTIAL_REGS_FOR_CVTSD2SS \ + (x86_sse_partial_regs_for_cvtsd2ss & TUNEMASK) #define TARGET_SSE_TYPELESS_STORES (x86_sse_typeless_stores & TUNEMASK) +#define TARGET_SSE_TYPELESS_LOAD0 (x86_sse_typeless_load0 & TUNEMASK) #define TARGET_SSE_LOAD0_BY_PXOR (x86_sse_load0_by_pxor & TUNEMASK) #define TARGET_MEMORY_MISMATCH_STALL (x86_memory_mismatch_stall & TUNEMASK) #define TARGET_PROLOGUE_USING_MOVE (x86_prologue_using_move & TUNEMASK) #define TARGET_EPILOGUE_USING_MOVE (x86_epilogue_using_move & TUNEMASK) +#define TARGET_DECOMPOSE_LEA (x86_decompose_lea & TUNEMASK) #define TARGET_PREFETCH_SSE (x86_prefetch_sse) #define TARGET_SHIFT1 (x86_shift1 & TUNEMASK) #define TARGET_USE_FFREEP (x86_use_ffreep & TUNEMASK) #define TARGET_REP_MOVL_OPTIMAL (x86_rep_movl_optimal & TUNEMASK) #define TARGET_INTER_UNIT_MOVES (x86_inter_unit_moves & TUNEMASK) -#define TARGET_FOUR_JUMP_LIMIT (x86_four_jump_limit & TUNEMASK) -#define TARGET_SCHEDULE (x86_schedule & TUNEMASK) -#define TARGET_USE_BT (x86_use_bt & TUNEMASK) -#define TARGET_USE_INCDEC (x86_use_incdec & TUNEMASK) -#define TARGET_PAD_RETURNS (x86_pad_returns & TUNEMASK) + +#define TARGET_STACK_PROBE (target_flags & MASK_STACK_PROBE) + +#define TARGET_ALIGN_STRINGOPS (!(target_flags & MASK_NO_ALIGN_STROPS)) +#define TARGET_INLINE_ALL_STRINGOPS (target_flags & MASK_INLINE_ALL_STROPS) #define ASSEMBLER_DIALECT (ix86_asm_dialect) +#define TARGET_SSE ((target_flags & MASK_SSE) != 0) +#define TARGET_SSE2 ((target_flags & MASK_SSE2) != 0) +#define TARGET_SSE3 ((target_flags & MASK_SSE3) != 0) #define TARGET_SSE_MATH ((ix86_fpmath & FPMATH_SSE) != 0) #define TARGET_MIX_SSE_I387 ((ix86_fpmath & FPMATH_SSE) \ && (ix86_fpmath & FPMATH_387)) +#define TARGET_MMX ((target_flags & MASK_MMX) != 0) +#define TARGET_3DNOW ((target_flags & MASK_3DNOW) != 0) +#define TARGET_3DNOW_A ((target_flags & MASK_3DNOW_A) != 0) + +#define TARGET_RED_ZONE (!(target_flags & MASK_NO_RED_ZONE)) + +#define TARGET_NO_ALIGN_LONG_STRINGS (target_flags & MASK_NO_ALIGN_LONG_STRINGS) + +#define TARGET_USE_MS_BITFIELD_LAYOUT (target_flags & MASK_MS_BITFIELD_LAYOUT) #define TARGET_GNU_TLS (ix86_tls_dialect == TLS_DIALECT_GNU) -#define TARGET_GNU2_TLS (ix86_tls_dialect == TLS_DIALECT_GNU2) -#define TARGET_ANY_GNU_TLS (TARGET_GNU_TLS || TARGET_GNU2_TLS) #define TARGET_SUN_TLS (ix86_tls_dialect == TLS_DIALECT_SUN) -#define TARGET_CMPXCHG (x86_cmpxchg & (1 << ix86_arch)) -#define TARGET_CMPXCHG8B (x86_cmpxchg8b & (1 << ix86_arch)) -#define TARGET_CMPXCHG16B (x86_cmpxchg16b & (1 << ix86_arch)) -#define TARGET_XADD (x86_xadd & (1 << ix86_arch)) +/* WARNING: Do not mark empty strings for translation, as calling + gettext on an empty string does NOT return an empty + string. */ + + +#define TARGET_SWITCHES \ +{ { "80387", MASK_80387, N_("Use hardware fp") }, \ + { "no-80387", -MASK_80387, N_("Do not use hardware fp") }, \ + { "hard-float", MASK_80387, N_("Use hardware fp") }, \ + { "soft-float", -MASK_80387, N_("Do not use hardware fp") }, \ + { "no-soft-float", MASK_80387, N_("Use hardware fp") }, \ + { "386", 0, "" /*Deprecated.*/}, \ + { "486", 0, "" /*Deprecated.*/}, \ + { "pentium", 0, "" /*Deprecated.*/}, \ + { "pentiumpro", 0, "" /*Deprecated.*/}, \ + { "pni", 0, "" /*Deprecated.*/}, \ + { "no-pni", 0, "" /*Deprecated.*/}, \ + { "intel-syntax", 0, "" /*Deprecated.*/}, \ + { "no-intel-syntax", 0, "" /*Deprecated.*/}, \ + { "rtd", MASK_RTD, \ + N_("Alternate calling convention") }, \ + { "no-rtd", -MASK_RTD, \ + N_("Use normal calling convention") }, \ + { "align-double", MASK_ALIGN_DOUBLE, \ + N_("Align some doubles on dword boundary") }, \ + { "no-align-double", -MASK_ALIGN_DOUBLE, \ + N_("Align doubles on word boundary") }, \ + { "svr3-shlib", MASK_SVR3_SHLIB, \ + N_("Uninitialized locals in .bss") }, \ + { "no-svr3-shlib", -MASK_SVR3_SHLIB, \ + N_("Uninitialized locals in .data") }, \ + { "ieee-fp", MASK_IEEE_FP, \ + N_("Use IEEE math for fp comparisons") }, \ + { "no-ieee-fp", -MASK_IEEE_FP, \ + N_("Do not use IEEE math for fp comparisons") }, \ + { "fp-ret-in-387", MASK_FLOAT_RETURNS, \ + N_("Return values of functions in FPU registers") }, \ + { "no-fp-ret-in-387", -MASK_FLOAT_RETURNS , \ + N_("Do not return values of functions in FPU registers")}, \ + { "no-fancy-math-387", MASK_NO_FANCY_MATH_387, \ + N_("Do not generate sin, cos, sqrt for FPU") }, \ + { "fancy-math-387", -MASK_NO_FANCY_MATH_387, \ + N_("Generate sin, cos, sqrt for FPU")}, \ + { "omit-leaf-frame-pointer", MASK_OMIT_LEAF_FRAME_POINTER, \ + N_("Omit the frame pointer in leaf functions") }, \ + { "no-omit-leaf-frame-pointer",-MASK_OMIT_LEAF_FRAME_POINTER, "" }, \ + { "stack-arg-probe", MASK_STACK_PROBE, \ + N_("Enable stack probing") }, \ + { "no-stack-arg-probe", -MASK_STACK_PROBE, "" }, \ + { "windows", 0, 0 /* undocumented */ }, \ + { "dll", 0, 0 /* undocumented */ }, \ + { "align-stringops", -MASK_NO_ALIGN_STROPS, \ + N_("Align destination of the string operations") }, \ + { "no-align-stringops", MASK_NO_ALIGN_STROPS, \ + N_("Do not align destination of the string operations") }, \ + { "inline-all-stringops", MASK_INLINE_ALL_STROPS, \ + N_("Inline all known string operations") }, \ + { "no-inline-all-stringops", -MASK_INLINE_ALL_STROPS, \ + N_("Do not inline all known string operations") }, \ + { "push-args", -MASK_NO_PUSH_ARGS, \ + N_("Use push instructions to save outgoing arguments") }, \ + { "no-push-args", MASK_NO_PUSH_ARGS, \ + N_("Do not use push instructions to save outgoing arguments") }, \ + { "accumulate-outgoing-args", MASK_ACCUMULATE_OUTGOING_ARGS, \ + N_("Use push instructions to save outgoing arguments") }, \ + { "no-accumulate-outgoing-args",-MASK_ACCUMULATE_OUTGOING_ARGS, \ + N_("Do not use push instructions to save outgoing arguments") }, \ + { "mmx", MASK_MMX, \ + N_("Support MMX built-in functions") }, \ + { "no-mmx", -MASK_MMX, \ + N_("Do not support MMX built-in functions") }, \ + { "3dnow", MASK_3DNOW, \ + N_("Support 3DNow! built-in functions") }, \ + { "no-3dnow", -MASK_3DNOW, \ + N_("Do not support 3DNow! built-in functions") }, \ + { "sse", MASK_SSE, \ + N_("Support MMX and SSE built-in functions and code generation") }, \ + { "no-sse", -MASK_SSE, \ + N_("Do not support MMX and SSE built-in functions and code generation") },\ + { "sse2", MASK_SSE2, \ + N_("Support MMX, SSE and SSE2 built-in functions and code generation") }, \ + { "no-sse2", -MASK_SSE2, \ + N_("Do not support MMX, SSE and SSE2 built-in functions and code generation") }, \ + { "sse3", MASK_SSE3, \ + N_("Support MMX, SSE, SSE2 and SSE3 built-in functions and code generation") },\ + { "no-sse3", -MASK_SSE3, \ + N_("Do not support MMX, SSE, SSE2 and SSE3 built-in functions and code generation") },\ + { "128bit-long-double", MASK_128BIT_LONG_DOUBLE, \ + N_("sizeof(long double) is 16") }, \ + { "96bit-long-double", -MASK_128BIT_LONG_DOUBLE, \ + N_("sizeof(long double) is 12") }, \ + { "64", MASK_64BIT, \ + N_("Generate 64bit x86-64 code") }, \ + { "32", -MASK_64BIT, \ + N_("Generate 32bit i386 code") }, \ + { "ms-bitfields", MASK_MS_BITFIELD_LAYOUT, \ + N_("Use native (MS) bitfield layout") }, \ + { "no-ms-bitfields", -MASK_MS_BITFIELD_LAYOUT, \ + N_("Use gcc default bitfield layout") }, \ + { "red-zone", -MASK_NO_RED_ZONE, \ + N_("Use red-zone in the x86-64 code") }, \ + { "no-red-zone", MASK_NO_RED_ZONE, \ + N_("Do not use red-zone in the x86-64 code") }, \ + { "no-align-long-strings", MASK_NO_ALIGN_LONG_STRINGS, \ + N_("Do not align long strings specially") }, \ + { "align-long-strings", -MASK_NO_ALIGN_LONG_STRINGS, \ + N_("Align strings longer than 30 on a 32-byte boundary") }, \ + { "tls-direct-seg-refs", MASK_TLS_DIRECT_SEG_REFS, \ + N_("Use direct references against %gs when accessing tls data") }, \ + { "no-tls-direct-seg-refs", -MASK_TLS_DIRECT_SEG_REFS, \ + N_("Do not use direct references against %gs when accessing tls data") }, \ + SUBTARGET_SWITCHES \ + { "", \ + TARGET_DEFAULT | TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_DEFAULT \ + | TARGET_TLS_DIRECT_SEG_REFS_DEFAULT, 0 }} #ifndef TARGET_64BIT_DEFAULT #define TARGET_64BIT_DEFAULT 0 @@ -259,6 +458,48 @@ extern int x86_prefetch_sse; with the rounding mode forced to 53 bits. */ #define TARGET_96_ROUND_53_LONG_DOUBLE 0 +/* This macro is similar to `TARGET_SWITCHES' but defines names of + command options that have values. Its definition is an + initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + fixed part of the option name, and the address of a variable. The + variable, type `char *', is set to the variable part of the given + option if the fixed part matches. The actual option name is made + by appending `-m' to the specified name. */ +#define TARGET_OPTIONS \ +{ { "tune=", &ix86_tune_string, \ + N_("Schedule code for given CPU"), 0}, \ + { "fpmath=", &ix86_fpmath_string, \ + N_("Generate floating point mathematics using given instruction set"), 0},\ + { "arch=", &ix86_arch_string, \ + N_("Generate code for given CPU"), 0}, \ + { "regparm=", &ix86_regparm_string, \ + N_("Number of registers used to pass integer arguments"), 0},\ + { "align-loops=", &ix86_align_loops_string, \ + N_("Loop code aligned to this power of 2"), 0}, \ + { "align-jumps=", &ix86_align_jumps_string, \ + N_("Jump targets are aligned to this power of 2"), 0}, \ + { "align-functions=", &ix86_align_funcs_string, \ + N_("Function starts are aligned to this power of 2"), 0}, \ + { "preferred-stack-boundary=", \ + &ix86_preferred_stack_boundary_string, \ + N_("Attempt to keep stack aligned to this power of 2"), 0}, \ + { "branch-cost=", &ix86_branch_cost_string, \ + N_("Branches are this expensive (1-5, arbitrary units)"), 0},\ + { "cmodel=", &ix86_cmodel_string, \ + N_("Use given x86-64 code model"), 0}, \ + { "debug-arg", &ix86_debug_arg_string, \ + "" /* Undocumented. */, 0}, \ + { "debug-addr", &ix86_debug_addr_string, \ + "" /* Undocumented. */, 0}, \ + { "asm=", &ix86_asm_string, \ + N_("Use given assembler dialect"), 0}, \ + { "tls-dialect=", &ix86_tls_dialect_string, \ + N_("Use given thread-local storage dialect"), 0}, \ + SUBTARGET_OPTIONS \ +} + /* Sometimes certain combinations of command options do not make sense on a particular target machine. You can define a macro `OVERRIDE_OPTIONS' to take account of this. This macro, if @@ -270,33 +511,24 @@ extern int x86_prefetch_sse; #define OVERRIDE_OPTIONS override_options () +/* These are meant to be redefined in the host dependent files */ +#define SUBTARGET_SWITCHES +#define SUBTARGET_OPTIONS + /* Define this to change the optimizations performed by default. */ #define OPTIMIZATION_OPTIONS(LEVEL, SIZE) \ optimization_options ((LEVEL), (SIZE)) -/* -march=native handling only makes sense with compiler running on - an x86 or x86_64 chip. If changing this condition, also change - the condition in driver-i386.c. */ -#if defined(__i386__) || defined(__x86_64__) -/* In driver-i386.c. */ -extern const char *host_detect_local_cpu (int argc, const char **argv); -#define EXTRA_SPEC_FUNCTIONS \ - { "local_cpu_detect", host_detect_local_cpu }, -#define HAVE_LOCAL_CPU_DETECT -#endif - -/* Support for configure-time defaults of some command line options. - The order here is important so that -march doesn't squash the - tune or cpu values. */ +/* Support for configure-time defaults of some command line options. */ #define OPTION_DEFAULT_SPECS \ + {"arch", "%{!march=*:-march=%(VALUE)}"}, \ {"tune", "%{!mtune=*:%{!mcpu=*:%{!march=*:-mtune=%(VALUE)}}}" }, \ - {"cpu", "%{!mtune=*:%{!mcpu=*:%{!march=*:-mtune=%(VALUE)}}}" }, \ - {"arch", "%{!march=*:-march=%(VALUE)}"} + {"cpu", "%{!mtune=*:%{!mcpu=*:%{!march=*:-mtune=%(VALUE)}}}" } /* Specs for the compiler proper */ #ifndef CC1_CPU_SPEC -#define CC1_CPU_SPEC_1 "\ +#define CC1_CPU_SPEC "\ %{!mtune*: \ %{m386:mtune=i386 \ %n`-m386' is deprecated. Use `-march=i386' or `-mtune=i386' instead.\n} \ @@ -309,19 +541,14 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); %{mcpu=*:-mtune=%* \ %n`-mcpu=' is deprecated. Use `-mtune=' or '-march=' instead.\n}} \ %<mcpu=* \ +%{mpni:-msse3 \ +%n`-mpni' is deprecated. Use `-msse3' instead.\n} \ +%{mno-pni:-mno-sse3 \ +%n`-mno-pni' is deprecated. Use `-mno-sse3' instead.\n} \ %{mintel-syntax:-masm=intel \ %n`-mintel-syntax' is deprecated. Use `-masm=intel' instead.\n} \ %{mno-intel-syntax:-masm=att \ %n`-mno-intel-syntax' is deprecated. Use `-masm=att' instead.\n}" - -#ifndef HAVE_LOCAL_CPU_DETECT -#define CC1_CPU_SPEC CC1_CPU_SPEC_1 -#else -#define CC1_CPU_SPEC CC1_CPU_SPEC_1 \ -"%{march=native:%<march=native %:local_cpu_detect(arch) \ - %{!mtune=*:%<mtune=native %:local_cpu_detect(tune)}} \ -%{mtune=native:%<mtune=native %:local_cpu_detect(tune)}" -#endif #endif /* Target CPU builtins. */ @@ -387,16 +614,14 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); else if (TARGET_ATHLON) \ { \ builtin_define ("__tune_athlon__"); \ - /* Only plain "athlon" lacks SSE. */ \ - if (last_tune_char != 'n') \ + /* Plain "athlon" & "athlon-tbird" lacks SSE. */ \ + if (last_tune_char != 'n' && last_tune_char != 'd') \ builtin_define ("__tune_athlon_sse__"); \ } \ else if (TARGET_K8) \ builtin_define ("__tune_k8__"); \ else if (TARGET_PENTIUM4) \ builtin_define ("__tune_pentium4__"); \ - else if (TARGET_NOCONA) \ - builtin_define ("__tune_nocona__"); \ \ if (TARGET_MMX) \ builtin_define ("__MMX__"); \ @@ -409,7 +634,10 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); if (TARGET_SSE2) \ builtin_define ("__SSE2__"); \ if (TARGET_SSE3) \ - builtin_define ("__SSE3__"); \ + { \ + builtin_define ("__SSE3__"); \ + builtin_define ("__PNI__"); \ + } \ if (TARGET_SSE_MATH && TARGET_SSE) \ builtin_define ("__SSE_MATH__"); \ if (TARGET_SSE_MATH && TARGET_SSE2) \ @@ -451,8 +679,8 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); { \ builtin_define ("__athlon"); \ builtin_define ("__athlon__"); \ - /* Only plain "athlon" lacks SSE. */ \ - if (last_arch_char != 'n') \ + /* Plain "athlon" & "athlon-tbird" lacks SSE. */ \ + if (last_tune_char != 'n' && last_tune_char != 'd') \ builtin_define ("__athlon_sse__"); \ } \ else if (ix86_arch == PROCESSOR_K8) \ @@ -465,11 +693,6 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); builtin_define ("__pentium4"); \ builtin_define ("__pentium4__"); \ } \ - else if (ix86_arch == PROCESSOR_NOCONA) \ - { \ - builtin_define ("__nocona"); \ - builtin_define ("__nocona__"); \ - } \ } \ while (0) @@ -490,14 +713,12 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #define TARGET_CPU_DEFAULT_pentium_m 14 #define TARGET_CPU_DEFAULT_prescott 15 #define TARGET_CPU_DEFAULT_nocona 16 -#define TARGET_CPU_DEFAULT_generic 17 #define TARGET_CPU_DEFAULT_NAMES {"i386", "i486", "pentium", "pentium-mmx",\ "pentiumpro", "pentium2", "pentium3", \ "pentium4", "k6", "k6-2", "k6-3",\ "athlon", "athlon-4", "k8", \ - "pentium-m", "prescott", "nocona", \ - "generic"} + "pentium-m", "prescott", "nocona"} #ifndef CC1_SPEC #define CC1_SPEC "%(cc1_cpu) " @@ -523,7 +744,7 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); /* target machine storage layout */ -#define LONG_DOUBLE_TYPE_SIZE 80 +#define LONG_DOUBLE_TYPE_SIZE 96 /* Set the value of FLT_EVAL_METHOD in float.h. When using only the FPU, assume that the fpcw is set to extended precision; when using @@ -536,14 +757,19 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #define SHORT_TYPE_SIZE 16 #define INT_TYPE_SIZE 32 #define FLOAT_TYPE_SIZE 32 +#ifndef LONG_TYPE_SIZE #define LONG_TYPE_SIZE BITS_PER_WORD +#endif +#define MAX_WCHAR_TYPE_SIZE 32 #define DOUBLE_TYPE_SIZE 64 #define LONG_LONG_TYPE_SIZE 64 #if defined (TARGET_BI_ARCH) || TARGET_64BIT_DEFAULT #define MAX_BITS_PER_WORD 64 +#define MAX_LONG_TYPE_SIZE 64 #else #define MAX_BITS_PER_WORD 32 +#define MAX_LONG_TYPE_SIZE 32 #endif /* Define this if most significant byte of a word is the lowest numbered. */ @@ -578,7 +804,7 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); aligned; the compiler cannot rely on having this alignment. */ #define PREFERRED_STACK_BOUNDARY ix86_preferred_stack_boundary -/* As of July 2001, many runtimes do not align the stack properly when +/* As of July 2001, many runtimes to not align the stack properly when entering main. This causes expand_main_function to forcibly align the stack, which results in aligned frames for functions called from main, though it does nothing for the alignment of main itself. */ @@ -607,7 +833,7 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); /* Decide whether a variable of mode MODE should be 128 bit aligned. */ #define ALIGN_MODE_128(MODE) \ - ((MODE) == XFmode || SSE_REG_MODE_P (MODE)) + ((MODE) == XFmode || (MODE) == TFmode || SSE_REG_MODE_P (MODE)) /* The published ABIs say that doubles should be aligned on word boundaries, so lower the alignment for structure fields unless @@ -690,9 +916,7 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #define STACK_REGS #define IS_STACK_MODE(MODE) \ - (((MODE) == SFmode && (!TARGET_SSE || !TARGET_SSE_MATH)) \ - || ((MODE) == DFmode && (!TARGET_SSE2 || !TARGET_SSE_MATH)) \ - || (MODE) == XFmode) + ((MODE) == DFmode || (MODE) == SFmode || (MODE) == XFmode) \ /* Number of actual hardware registers. The hardware registers are assigned numbers for the compiler @@ -721,25 +945,23 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); and are not available for the register allocator. On the 80386, the stack pointer is such, as is the arg pointer. - The value is zero if the register is not fixed on either 32 or - 64 bit targets, one if the register if fixed on both 32 and 64 - bit targets, two if it is only fixed on 32bit targets and three - if its only fixed on 64bit targets. - Proper values are computed in the CONDITIONAL_REGISTER_USAGE. + The value is a mask - bit 1 is set for fixed registers + for 32bit target, while 2 is set for fixed registers for 64bit. + Proper value is computed in the CONDITIONAL_REGISTER_USAGE. */ #define FIXED_REGISTERS \ /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7*/ \ -{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, \ +{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, \ /*arg,flags,fpsr,dir,frame*/ \ - 1, 1, 1, 1, 1, \ + 3, 3, 3, 3, 3, \ /*xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7*/ \ 0, 0, 0, 0, 0, 0, 0, 0, \ /*mmx0,mmx1,mmx2,mmx3,mmx4,mmx5,mmx6,mmx7*/ \ 0, 0, 0, 0, 0, 0, 0, 0, \ /* r8, r9, r10, r11, r12, r13, r14, r15*/ \ - 2, 2, 2, 2, 2, 2, 2, 2, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ /*xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15*/ \ - 2, 2, 2, 2, 2, 2, 2, 2} + 1, 1, 1, 1, 1, 1, 1, 1} /* 1 for registers not available across function calls. @@ -749,25 +971,23 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); and the register where structure-value addresses are passed. Aside from that, you can include as many other registers as you like. - The value is zero if the register is not call used on either 32 or - 64 bit targets, one if the register if call used on both 32 and 64 - bit targets, two if it is only call used on 32bit targets and three - if its only call used on 64bit targets. - Proper values are computed in the CONDITIONAL_REGISTER_USAGE. + The value is a mask - bit 1 is set for call used + for 32bit target, while 2 is set for call used for 64bit. + Proper value is computed in the CONDITIONAL_REGISTER_USAGE. */ #define CALL_USED_REGISTERS \ /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7*/ \ -{ 1, 1, 1, 0, 3, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ +{ 3, 3, 3, 0, 2, 2, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, \ /*arg,flags,fpsr,dir,frame*/ \ - 1, 1, 1, 1, 1, \ + 3, 3, 3, 3, 3, \ /*xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7*/ \ - 1, 1, 1, 1, 1, 1, 1, 1, \ + 3, 3, 3, 3, 3, 3, 3, 3, \ /*mmx0,mmx1,mmx2,mmx3,mmx4,mmx5,mmx6,mmx7*/ \ - 1, 1, 1, 1, 1, 1, 1, 1, \ + 3, 3, 3, 3, 3, 3, 3, 3, \ /* r8, r9, r10, r11, r12, r13, r14, r15*/ \ - 1, 1, 1, 1, 2, 2, 2, 2, \ + 3, 3, 3, 3, 1, 1, 1, 1, \ /*xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15*/ \ - 1, 1, 1, 1, 1, 1, 1, 1} \ + 3, 3, 3, 3, 3, 3, 3, 3} \ /* Order in which to allocate registers. Each register must be listed once, even those in FIXED_REGISTERS. List frame pointer @@ -797,11 +1017,9 @@ do { \ int i; \ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \ { \ - if (fixed_regs[i] > 1) \ - fixed_regs[i] = (fixed_regs[i] == (TARGET_64BIT ? 3 : 2)); \ - if (call_used_regs[i] > 1) \ - call_used_regs[i] = (call_used_regs[i] \ - == (TARGET_64BIT ? 3 : 2)); \ + fixed_regs[i] = (fixed_regs[i] & (TARGET_64BIT ? 2 : 1)) != 0; \ + call_used_regs[i] = (call_used_regs[i] \ + & (TARGET_64BIT ? 2 : 1)) != 0; \ } \ if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) \ { \ @@ -813,14 +1031,14 @@ do { \ int i; \ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \ if (TEST_HARD_REG_BIT (reg_class_contents[(int)MMX_REGS], i)) \ - fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = ""; \ + fixed_regs[i] = call_used_regs[i] = 1; \ } \ if (! TARGET_SSE) \ { \ int i; \ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \ if (TEST_HARD_REG_BIT (reg_class_contents[(int)SSE_REGS], i)) \ - fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = ""; \ + fixed_regs[i] = call_used_regs[i] = 1; \ } \ if (! TARGET_80387 && ! TARGET_FLOAT_RETURNS_IN_80387) \ { \ @@ -829,15 +1047,7 @@ do { \ COPY_HARD_REG_SET (x, reg_class_contents[(int)FLOAT_REGS]); \ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \ if (TEST_HARD_REG_BIT (x, i)) \ - fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = ""; \ - } \ - if (! TARGET_64BIT) \ - { \ - int i; \ - for (i = FIRST_REX_INT_REG; i <= LAST_REX_INT_REG; i++) \ - reg_names[i] = ""; \ - for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++) \ - reg_names[i] = ""; \ + fixed_regs[i] = call_used_regs[i] = 1; \ } \ } while (0) @@ -860,15 +1070,6 @@ do { \ ? (TARGET_64BIT ? 4 : 6) \ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))) -#define HARD_REGNO_NREGS_HAS_PADDING(REGNO, MODE) \ - ((TARGET_128BIT_LONG_DOUBLE && !TARGET_64BIT) \ - ? (FP_REGNO_P (REGNO) || SSE_REGNO_P (REGNO) || MMX_REGNO_P (REGNO) \ - ? 0 \ - : ((MODE) == XFmode || (MODE) == XCmode)) \ - : 0) - -#define HARD_REGNO_NREGS_WITH_PADDING(REGNO, MODE) ((MODE) == XFmode ? 4 : 8) - #define VALID_SSE2_REG_MODE(MODE) \ ((MODE) == V16QImode || (MODE) == V8HImode || (MODE) == V2DFmode \ || (MODE) == V2DImode || (MODE) == DFmode) @@ -884,9 +1085,10 @@ do { \ ((MODE) == DImode || (MODE) == V8QImode || (MODE) == V4HImode \ || (MODE) == V2SImode || (MODE) == SImode) -/* ??? No autovectorization into MMX or 3DNOW until we can reliably - place emms and femms instructions. */ -#define UNITS_PER_SIMD_WORD (TARGET_SSE ? 16 : UNITS_PER_WORD) +#define VECTOR_MODE_SUPPORTED_P(MODE) \ + (VALID_SSE_REG_MODE (MODE) && TARGET_SSE ? 1 \ + : VALID_MMX_REG_MODE (MODE) && TARGET_MMX ? 1 \ + : VALID_MMX_REG_MODE_3DNOW (MODE) && TARGET_3DNOW ? 1 : 0) #define VALID_FP_MODE_P(MODE) \ ((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode \ @@ -906,6 +1108,11 @@ do { \ || (MODE) == V8HImode || (MODE) == V2DFmode || (MODE) == V2DImode \ || (MODE) == V4SFmode || (MODE) == V4SImode) +/* Return true for modes passed in MMX registers. */ +#define MMX_REG_MODE_P(MODE) \ + ((MODE) == V8QImode || (MODE) == V4HImode || (MODE) == V2SImode \ + || (MODE) == V2SFmode) + /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ #define HARD_REGNO_MODE_OK(REGNO, MODE) \ @@ -916,7 +1123,16 @@ do { \ If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, for any hard reg, then this must be 0 for correct output. */ -#define MODES_TIEABLE_P(MODE1, MODE2) ix86_modes_tieable_p (MODE1, MODE2) +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ((MODE1) == (MODE2) \ + || (((MODE1) == HImode || (MODE1) == SImode \ + || ((MODE1) == QImode \ + && (TARGET_64BIT || !TARGET_PARTIAL_REG_STALL)) \ + || ((MODE1) == DImode && TARGET_64BIT)) \ + && ((MODE2) == HImode || (MODE2) == SImode \ + || ((MODE2) == QImode \ + && (TARGET_64BIT || !TARGET_PARTIAL_REG_STALL)) \ + || ((MODE2) == DImode && TARGET_64BIT)))) /* It is possible to write patterns to move flags; but until someone does it, */ @@ -957,6 +1173,10 @@ do { \ #define FIRST_STACK_REG FIRST_FLOAT_REG #define LAST_STACK_REG (FIRST_FLOAT_REG + 7) +#define FLAGS_REG 17 +#define FPSR_REG 18 +#define DIRFLAG_REG 19 + #define FIRST_SSE_REG (FRAME_POINTER_REGNUM + 1) #define LAST_SSE_REG (FIRST_SSE_REG + 7) @@ -975,7 +1195,7 @@ do { \ This is computed in `reload', in reload1.c. */ #define FRAME_POINTER_REQUIRED ix86_frame_pointer_required () -/* Override this in other tm.h files to cope with various OS lossage +/* Override this in other tm.h files to cope with various OS losage requiring a frame pointer. */ #ifndef SUBTARGET_FRAME_POINTER_REQUIRED #define SUBTARGET_FRAME_POINTER_REQUIRED 0 @@ -1004,13 +1224,21 @@ do { \ #define REAL_PIC_OFFSET_TABLE_REGNUM 3 #define PIC_OFFSET_TABLE_REGNUM \ - ((TARGET_64BIT && ix86_cmodel == CM_SMALL_PIC) \ - || !flag_pic ? INVALID_REGNUM \ + (TARGET_64BIT || !flag_pic ? INVALID_REGNUM \ : reload_completed ? REGNO (pic_offset_table_rtx) \ : REAL_PIC_OFFSET_TABLE_REGNUM) #define GOT_SYMBOL_NAME "_GLOBAL_OFFSET_TABLE_" +/* Register in which address to store a structure value + arrives in the function. On the 386, the prologue + copies this from the stack to register %eax. */ +#define STRUCT_VALUE_INCOMING 0 + +/* Place in which caller passes the structure value address. + 0 means push the value on the stack like an argument. */ +#define STRUCT_VALUE 0 + /* A C expression which can inhibit the returning of certain function values in registers, based on the type of value. A nonzero value says to return the function value in memory, just as large @@ -1034,8 +1262,6 @@ do { \ /* This is overridden by <cygwin.h>. */ #define MS_AGGREGATE_RETURN 0 -/* This is overridden by <netware.h>. */ -#define KEEP_AGGREGATE_RETURN_POINTER 0 /* Define the classes of registers for register constraints in the machine description. Also define ranges of constants. @@ -1093,9 +1319,9 @@ enum reg_class #define FLOAT_CLASS_P(CLASS) \ reg_class_subset_p ((CLASS), FLOAT_REGS) #define SSE_CLASS_P(CLASS) \ - ((CLASS) == SSE_REGS) + reg_class_subset_p ((CLASS), SSE_REGS) #define MMX_CLASS_P(CLASS) \ - ((CLASS) == MMX_REGS) + reg_class_subset_p ((CLASS), MMX_REGS) #define MAYBE_INTEGER_CLASS_P(CLASS) \ reg_classes_intersect_p ((CLASS), GENERAL_REGS) #define MAYBE_FLOAT_CLASS_P(CLASS) \ @@ -1228,6 +1454,83 @@ enum reg_class #define INDEX_REG_CLASS INDEX_REGS #define BASE_REG_CLASS GENERAL_REGS +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'r' ? GENERAL_REGS : \ + (C) == 'R' ? LEGACY_REGS : \ + (C) == 'q' ? TARGET_64BIT ? GENERAL_REGS : Q_REGS : \ + (C) == 'Q' ? Q_REGS : \ + (C) == 'f' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \ + ? FLOAT_REGS \ + : NO_REGS) : \ + (C) == 't' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \ + ? FP_TOP_REG \ + : NO_REGS) : \ + (C) == 'u' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \ + ? FP_SECOND_REG \ + : NO_REGS) : \ + (C) == 'a' ? AREG : \ + (C) == 'b' ? BREG : \ + (C) == 'c' ? CREG : \ + (C) == 'd' ? DREG : \ + (C) == 'x' ? TARGET_SSE ? SSE_REGS : NO_REGS : \ + (C) == 'Y' ? TARGET_SSE2? SSE_REGS : NO_REGS : \ + (C) == 'y' ? TARGET_MMX ? MMX_REGS : NO_REGS : \ + (C) == 'A' ? AD_REGS : \ + (C) == 'D' ? DIREG : \ + (C) == 'S' ? SIREG : NO_REGS) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + I is for non-DImode shifts. + J is for DImode shifts. + K is for signed imm8 operands. + L is for andsi as zero-extending move. + M is for shifts that can be executed by the "lea" opcode. + N is for immediate operands for out/in instructions (0-255) + */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 31 \ + : (C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 63 \ + : (C) == 'K' ? (VALUE) >= -128 && (VALUE) <= 127 \ + : (C) == 'L' ? (VALUE) == 0xff || (VALUE) == 0xffff \ + : (C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 3 \ + : (C) == 'N' ? (VALUE) >= 0 && (VALUE) <= 255 \ + : 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. We allow constants even if + TARGET_387 isn't set, because the stack register converter may need to + load 0.0 into the function value register. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' ? standard_80387_constant_p (VALUE) \ + : 0) + +/* A C expression that defines the optional machine-dependent + constraint letters that can be used to segregate specific types of + operands, usually memory references, for the target machine. Any + letter that is not elsewhere defined and not matched by + `REG_CLASS_FROM_LETTER' may be used. Normally this macro will not + be defined. + + If it is required for a particular target machine, it should + return 1 if VALUE corresponds to the operand type represented by + the constraint letter C. If C is not defined as an extra + constraint, the value returned should be 0 regardless of VALUE. */ + +#define EXTRA_CONSTRAINT(VALUE, D) \ + ((D) == 'e' ? x86_64_sign_extended_value (VALUE) \ + : (D) == 'Z' ? x86_64_zero_extended_value (VALUE) \ + : (D) == 'C' ? standard_sse_constant_p (VALUE) \ + : 0) + /* Place additional restrictions on the register class to use when it is necessary to be able to hold a value of mode MODE in a reload register for which class CLASS would ordinarily be used. */ @@ -1254,12 +1557,6 @@ enum reg_class #define PREFERRED_RELOAD_CLASS(X, CLASS) \ ix86_preferred_reload_class ((X), (CLASS)) -/* Discourage putting floating-point values in SSE registers unless - SSE math is being used, and likewise for the 387 registers. */ - -#define PREFERRED_OUTPUT_RELOAD_CLASS(X, CLASS) \ - ix86_preferred_output_reload_class ((X), (CLASS)) - /* If we are copying between general and FP registers, we need a memory location. The same is true for SSE and MMX registers. */ #define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \ @@ -1311,10 +1608,35 @@ enum reg_class || ((CLASS) == FP_TOP_REG) \ || ((CLASS) == FP_SECOND_REG)) -/* Return a class of registers that cannot change FROM mode to TO mode. */ - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - ix86_cannot_change_mode_class (FROM, TO, CLASS) +/* Return a class of registers that cannot change FROM mode to TO mode. + + x87 registers can't do subreg as all values are reformated to extended + precision. XMM registers does not support with nonzero offsets equal + to 4, 8 and 12 otherwise valid for integer registers. Since we can't + determine these, prohibit all nonparadoxical subregs changing size. */ + +#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ + (GET_MODE_SIZE (TO) < GET_MODE_SIZE (FROM) \ + ? reg_classes_intersect_p (FLOAT_SSE_REGS, (CLASS)) \ + || MAYBE_MMX_CLASS_P (CLASS) \ + : GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \ + ? reg_classes_intersect_p (FLOAT_REGS, (CLASS)) : 0) + +/* A C statement that adds to CLOBBERS any hard regs the port wishes + to automatically clobber for all asms. + + We do this in the new i386 backend to maintain source compatibility + with the old cc0-based compiler. */ + +#define MD_ASM_CLOBBERS(CLOBBERS) \ + do { \ + (CLOBBERS) = tree_cons (NULL_TREE, build_string (5, "flags"), \ + (CLOBBERS)); \ + (CLOBBERS) = tree_cons (NULL_TREE, build_string (4, "fpsr"), \ + (CLOBBERS)); \ + (CLOBBERS) = tree_cons (NULL_TREE, build_string (7, "dirflag"), \ + (CLOBBERS)); \ + } while (0) /* Stack layout; function entry, exit and calling. */ @@ -1322,11 +1644,11 @@ enum reg_class makes the stack pointer a smaller address. */ #define STACK_GROWS_DOWNWARD -/* Define this to nonzero if the nominal address of the stack frame +/* Define this if the nominal address of the stack frame is at the high-address end of the local variables; that is, each additional local variable allocated goes at a more negative offset in the frame. */ -#define FRAME_GROWS_DOWNWARD 1 +#define FRAME_GROWS_DOWNWARD /* Offset within stack frame to start allocating local variables at. If FRAME_GROWS_DOWNWARD, this is the offset to the END of the @@ -1336,10 +1658,9 @@ enum reg_class /* If we generate an insn to push BYTES bytes, this says how many the stack pointer really advances by. - On 386, we have pushw instruction that decrements by exactly 2 no - matter what the position was, there is no pushb. - But as CIE data alignment factor on this arch is -4, we need to make - sure all stack pointer adjustments are in multiple of 4. + On 386 pushw decrements by exactly 2 no matter what the position was. + On the 386 there is no pushb; we use pushw instead, and this + has the effect of rounding up to 2. For 64bit ABI we round up to 8 bytes. */ @@ -1347,7 +1668,7 @@ enum reg_class #define PUSH_ROUNDING(BYTES) \ (TARGET_64BIT \ ? (((BYTES) + 7) & (-8)) \ - : (((BYTES) + 3) & (-4))) + : (((BYTES) + 1) & (-2))) /* If defined, the maximum amount of space required for outgoing arguments will be computed and placed into the variable @@ -1380,6 +1701,13 @@ enum reg_class which. */ #define REG_PARM_STACK_SPACE(FNDECL) 0 +/* Define as a C expression that evaluates to nonzero if we do not know how + to pass TYPE solely in registers. The file expr.h defines a + definition that is usually appropriate, refer to expr.h for additional + documentation. If `REG_PARM_STACK_SPACE' is defined, the argument will be + computed in the stack and then loaded into a register. */ +#define MUST_PASS_IN_STACK(MODE, TYPE) ix86_must_pass_in_stack ((MODE), (TYPE)) + /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. FUNDECL is the declaration node of the function (as a tree), @@ -1400,6 +1728,13 @@ enum reg_class #define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) \ ix86_return_pops_args ((FUNDECL), (FUNTYPE), (SIZE)) +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + ix86_function_value (VALTYPE) + #define FUNCTION_VALUE_REGNO_P(N) \ ix86_function_value_regno_p (N) @@ -1428,7 +1763,7 @@ typedef struct ix86_args { int words; /* # words passed so far */ int nregs; /* # registers available for passing */ int regno; /* next available register number */ - int fastcall; /* fastcall calling convention is used */ + int fastcall; /* fastcall calling convention is used */ int sse_words; /* # sse words passed so far */ int sse_nregs; /* # sse registers available for passing */ int warn_sse; /* True when we want to warn about SSE ABI. */ @@ -1438,8 +1773,6 @@ typedef struct ix86_args { int mmx_nregs; /* # mmx registers available for passing */ int mmx_regno; /* next available mmx register number */ int maybe_vaarg; /* true for calls to possibly vardic fncts. */ - int float_in_sse; /* 1 if in 32-bit mode SFmode (2 for DFmode) should - be passed in SSE registers. Otherwise 0. */ } CUMULATIVE_ARGS; /* Initialize a variable CUM of type CUMULATIVE_ARGS @@ -1472,10 +1805,47 @@ typedef struct ix86_args { #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ function_arg (&(CUM), (MODE), (TYPE), (NAMED)) +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0 + +/* A C expression that indicates when an argument must be passed by + reference. If nonzero for an argument, a copy of that argument is + made in memory and a pointer to the argument is passed instead of + the argument itself. The pointer is passed in whatever way is + appropriate for passing a pointer to that type. */ + +#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \ + function_arg_pass_by_reference(&CUM, MODE, TYPE, NAMED) + +/* Perform any needed actions needed for a function that is receiving a + variable number of arguments. + + CUM is as above. + + MODE and TYPE are the mode and type of the current parameter. + + PRETEND_SIZE is a variable that should be set to the amount of stack + that must be pushed by the prolog to pretend that our caller pushed + it. + + Normally, this macro will push all remaining incoming registers on the + stack and set PRETEND_SIZE to the length of the registers pushed. */ + +#define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PRETEND_SIZE, NO_RTL) \ + ix86_setup_incoming_varargs (&(CUM), (MODE), (TYPE), &(PRETEND_SIZE), \ + (NO_RTL)) + /* Implement `va_start' for varargs and stdarg. */ #define EXPAND_BUILTIN_VA_START(VALIST, NEXTARG) \ ix86_va_start (VALIST, NEXTARG) +/* Implement `va_arg'. */ +#define EXPAND_BUILTIN_VA_ARG(VALIST, TYPE) \ + ix86_va_arg ((VALIST), (TYPE)) + #define TARGET_ASM_FILE_END ix86_file_end #define NEED_INDICATE_EXEC_STACK 0 @@ -1599,7 +1969,7 @@ typedef struct ix86_args { been eliminated by then. */ -/* Non strict versions, pseudos are ok. */ +/* Non strict versions, pseudos are ok */ #define REG_OK_FOR_INDEX_NONSTRICT_P(X) \ (REGNO (X) < STACK_POINTER_REGNUM \ || (REGNO (X) >= FIRST_REX_INT_REG \ @@ -1726,6 +2096,462 @@ do { \ goto LABEL; \ } while (0) +/* Codes for all the SSE/MMX builtins. */ +enum ix86_builtins +{ + IX86_BUILTIN_ADDPS, + IX86_BUILTIN_ADDSS, + IX86_BUILTIN_DIVPS, + IX86_BUILTIN_DIVSS, + IX86_BUILTIN_MULPS, + IX86_BUILTIN_MULSS, + IX86_BUILTIN_SUBPS, + IX86_BUILTIN_SUBSS, + + IX86_BUILTIN_CMPEQPS, + IX86_BUILTIN_CMPLTPS, + IX86_BUILTIN_CMPLEPS, + IX86_BUILTIN_CMPGTPS, + IX86_BUILTIN_CMPGEPS, + IX86_BUILTIN_CMPNEQPS, + IX86_BUILTIN_CMPNLTPS, + IX86_BUILTIN_CMPNLEPS, + IX86_BUILTIN_CMPNGTPS, + IX86_BUILTIN_CMPNGEPS, + IX86_BUILTIN_CMPORDPS, + IX86_BUILTIN_CMPUNORDPS, + IX86_BUILTIN_CMPNEPS, + IX86_BUILTIN_CMPEQSS, + IX86_BUILTIN_CMPLTSS, + IX86_BUILTIN_CMPLESS, + IX86_BUILTIN_CMPNEQSS, + IX86_BUILTIN_CMPNLTSS, + IX86_BUILTIN_CMPNLESS, + IX86_BUILTIN_CMPORDSS, + IX86_BUILTIN_CMPUNORDSS, + IX86_BUILTIN_CMPNESS, + + IX86_BUILTIN_COMIEQSS, + IX86_BUILTIN_COMILTSS, + IX86_BUILTIN_COMILESS, + IX86_BUILTIN_COMIGTSS, + IX86_BUILTIN_COMIGESS, + IX86_BUILTIN_COMINEQSS, + IX86_BUILTIN_UCOMIEQSS, + IX86_BUILTIN_UCOMILTSS, + IX86_BUILTIN_UCOMILESS, + IX86_BUILTIN_UCOMIGTSS, + IX86_BUILTIN_UCOMIGESS, + IX86_BUILTIN_UCOMINEQSS, + + IX86_BUILTIN_CVTPI2PS, + IX86_BUILTIN_CVTPS2PI, + IX86_BUILTIN_CVTSI2SS, + IX86_BUILTIN_CVTSI642SS, + IX86_BUILTIN_CVTSS2SI, + IX86_BUILTIN_CVTSS2SI64, + IX86_BUILTIN_CVTTPS2PI, + IX86_BUILTIN_CVTTSS2SI, + IX86_BUILTIN_CVTTSS2SI64, + + IX86_BUILTIN_MAXPS, + IX86_BUILTIN_MAXSS, + IX86_BUILTIN_MINPS, + IX86_BUILTIN_MINSS, + + IX86_BUILTIN_LOADAPS, + IX86_BUILTIN_LOADUPS, + IX86_BUILTIN_STOREAPS, + IX86_BUILTIN_STOREUPS, + IX86_BUILTIN_LOADSS, + IX86_BUILTIN_STORESS, + IX86_BUILTIN_MOVSS, + + IX86_BUILTIN_MOVHLPS, + IX86_BUILTIN_MOVLHPS, + IX86_BUILTIN_LOADHPS, + IX86_BUILTIN_LOADLPS, + IX86_BUILTIN_STOREHPS, + IX86_BUILTIN_STORELPS, + + IX86_BUILTIN_MASKMOVQ, + IX86_BUILTIN_MOVMSKPS, + IX86_BUILTIN_PMOVMSKB, + + IX86_BUILTIN_MOVNTPS, + IX86_BUILTIN_MOVNTQ, + + IX86_BUILTIN_LOADDQA, + IX86_BUILTIN_LOADDQU, + IX86_BUILTIN_STOREDQA, + IX86_BUILTIN_STOREDQU, + IX86_BUILTIN_MOVQ, + IX86_BUILTIN_LOADD, + IX86_BUILTIN_STORED, + + IX86_BUILTIN_CLRTI, + + IX86_BUILTIN_PACKSSWB, + IX86_BUILTIN_PACKSSDW, + IX86_BUILTIN_PACKUSWB, + + IX86_BUILTIN_PADDB, + IX86_BUILTIN_PADDW, + IX86_BUILTIN_PADDD, + IX86_BUILTIN_PADDQ, + IX86_BUILTIN_PADDSB, + IX86_BUILTIN_PADDSW, + IX86_BUILTIN_PADDUSB, + IX86_BUILTIN_PADDUSW, + IX86_BUILTIN_PSUBB, + IX86_BUILTIN_PSUBW, + IX86_BUILTIN_PSUBD, + IX86_BUILTIN_PSUBQ, + IX86_BUILTIN_PSUBSB, + IX86_BUILTIN_PSUBSW, + IX86_BUILTIN_PSUBUSB, + IX86_BUILTIN_PSUBUSW, + + IX86_BUILTIN_PAND, + IX86_BUILTIN_PANDN, + IX86_BUILTIN_POR, + IX86_BUILTIN_PXOR, + + IX86_BUILTIN_PAVGB, + IX86_BUILTIN_PAVGW, + + IX86_BUILTIN_PCMPEQB, + IX86_BUILTIN_PCMPEQW, + IX86_BUILTIN_PCMPEQD, + IX86_BUILTIN_PCMPGTB, + IX86_BUILTIN_PCMPGTW, + IX86_BUILTIN_PCMPGTD, + + IX86_BUILTIN_PEXTRW, + IX86_BUILTIN_PINSRW, + + IX86_BUILTIN_PMADDWD, + + IX86_BUILTIN_PMAXSW, + IX86_BUILTIN_PMAXUB, + IX86_BUILTIN_PMINSW, + IX86_BUILTIN_PMINUB, + + IX86_BUILTIN_PMULHUW, + IX86_BUILTIN_PMULHW, + IX86_BUILTIN_PMULLW, + + IX86_BUILTIN_PSADBW, + IX86_BUILTIN_PSHUFW, + + IX86_BUILTIN_PSLLW, + IX86_BUILTIN_PSLLD, + IX86_BUILTIN_PSLLQ, + IX86_BUILTIN_PSRAW, + IX86_BUILTIN_PSRAD, + IX86_BUILTIN_PSRLW, + IX86_BUILTIN_PSRLD, + IX86_BUILTIN_PSRLQ, + IX86_BUILTIN_PSLLWI, + IX86_BUILTIN_PSLLDI, + IX86_BUILTIN_PSLLQI, + IX86_BUILTIN_PSRAWI, + IX86_BUILTIN_PSRADI, + IX86_BUILTIN_PSRLWI, + IX86_BUILTIN_PSRLDI, + IX86_BUILTIN_PSRLQI, + + IX86_BUILTIN_PUNPCKHBW, + IX86_BUILTIN_PUNPCKHWD, + IX86_BUILTIN_PUNPCKHDQ, + IX86_BUILTIN_PUNPCKLBW, + IX86_BUILTIN_PUNPCKLWD, + IX86_BUILTIN_PUNPCKLDQ, + + IX86_BUILTIN_SHUFPS, + + IX86_BUILTIN_RCPPS, + IX86_BUILTIN_RCPSS, + IX86_BUILTIN_RSQRTPS, + IX86_BUILTIN_RSQRTSS, + IX86_BUILTIN_SQRTPS, + IX86_BUILTIN_SQRTSS, + + IX86_BUILTIN_UNPCKHPS, + IX86_BUILTIN_UNPCKLPS, + + IX86_BUILTIN_ANDPS, + IX86_BUILTIN_ANDNPS, + IX86_BUILTIN_ORPS, + IX86_BUILTIN_XORPS, + + IX86_BUILTIN_EMMS, + IX86_BUILTIN_LDMXCSR, + IX86_BUILTIN_STMXCSR, + IX86_BUILTIN_SFENCE, + + /* 3DNow! Original */ + IX86_BUILTIN_FEMMS, + IX86_BUILTIN_PAVGUSB, + IX86_BUILTIN_PF2ID, + IX86_BUILTIN_PFACC, + IX86_BUILTIN_PFADD, + IX86_BUILTIN_PFCMPEQ, + IX86_BUILTIN_PFCMPGE, + IX86_BUILTIN_PFCMPGT, + IX86_BUILTIN_PFMAX, + IX86_BUILTIN_PFMIN, + IX86_BUILTIN_PFMUL, + IX86_BUILTIN_PFRCP, + IX86_BUILTIN_PFRCPIT1, + IX86_BUILTIN_PFRCPIT2, + IX86_BUILTIN_PFRSQIT1, + IX86_BUILTIN_PFRSQRT, + IX86_BUILTIN_PFSUB, + IX86_BUILTIN_PFSUBR, + IX86_BUILTIN_PI2FD, + IX86_BUILTIN_PMULHRW, + + /* 3DNow! Athlon Extensions */ + IX86_BUILTIN_PF2IW, + IX86_BUILTIN_PFNACC, + IX86_BUILTIN_PFPNACC, + IX86_BUILTIN_PI2FW, + IX86_BUILTIN_PSWAPDSI, + IX86_BUILTIN_PSWAPDSF, + + IX86_BUILTIN_SSE_ZERO, + IX86_BUILTIN_MMX_ZERO, + + /* SSE2 */ + IX86_BUILTIN_ADDPD, + IX86_BUILTIN_ADDSD, + IX86_BUILTIN_DIVPD, + IX86_BUILTIN_DIVSD, + IX86_BUILTIN_MULPD, + IX86_BUILTIN_MULSD, + IX86_BUILTIN_SUBPD, + IX86_BUILTIN_SUBSD, + + IX86_BUILTIN_CMPEQPD, + IX86_BUILTIN_CMPLTPD, + IX86_BUILTIN_CMPLEPD, + IX86_BUILTIN_CMPGTPD, + IX86_BUILTIN_CMPGEPD, + IX86_BUILTIN_CMPNEQPD, + IX86_BUILTIN_CMPNLTPD, + IX86_BUILTIN_CMPNLEPD, + IX86_BUILTIN_CMPNGTPD, + IX86_BUILTIN_CMPNGEPD, + IX86_BUILTIN_CMPORDPD, + IX86_BUILTIN_CMPUNORDPD, + IX86_BUILTIN_CMPNEPD, + IX86_BUILTIN_CMPEQSD, + IX86_BUILTIN_CMPLTSD, + IX86_BUILTIN_CMPLESD, + IX86_BUILTIN_CMPNEQSD, + IX86_BUILTIN_CMPNLTSD, + IX86_BUILTIN_CMPNLESD, + IX86_BUILTIN_CMPORDSD, + IX86_BUILTIN_CMPUNORDSD, + IX86_BUILTIN_CMPNESD, + + IX86_BUILTIN_COMIEQSD, + IX86_BUILTIN_COMILTSD, + IX86_BUILTIN_COMILESD, + IX86_BUILTIN_COMIGTSD, + IX86_BUILTIN_COMIGESD, + IX86_BUILTIN_COMINEQSD, + IX86_BUILTIN_UCOMIEQSD, + IX86_BUILTIN_UCOMILTSD, + IX86_BUILTIN_UCOMILESD, + IX86_BUILTIN_UCOMIGTSD, + IX86_BUILTIN_UCOMIGESD, + IX86_BUILTIN_UCOMINEQSD, + + IX86_BUILTIN_MAXPD, + IX86_BUILTIN_MAXSD, + IX86_BUILTIN_MINPD, + IX86_BUILTIN_MINSD, + + IX86_BUILTIN_ANDPD, + IX86_BUILTIN_ANDNPD, + IX86_BUILTIN_ORPD, + IX86_BUILTIN_XORPD, + + IX86_BUILTIN_SQRTPD, + IX86_BUILTIN_SQRTSD, + + IX86_BUILTIN_UNPCKHPD, + IX86_BUILTIN_UNPCKLPD, + + IX86_BUILTIN_SHUFPD, + + IX86_BUILTIN_LOADAPD, + IX86_BUILTIN_LOADUPD, + IX86_BUILTIN_STOREAPD, + IX86_BUILTIN_STOREUPD, + IX86_BUILTIN_LOADSD, + IX86_BUILTIN_STORESD, + IX86_BUILTIN_MOVSD, + + IX86_BUILTIN_LOADHPD, + IX86_BUILTIN_LOADLPD, + IX86_BUILTIN_STOREHPD, + IX86_BUILTIN_STORELPD, + + IX86_BUILTIN_CVTDQ2PD, + IX86_BUILTIN_CVTDQ2PS, + + IX86_BUILTIN_CVTPD2DQ, + IX86_BUILTIN_CVTPD2PI, + IX86_BUILTIN_CVTPD2PS, + IX86_BUILTIN_CVTTPD2DQ, + IX86_BUILTIN_CVTTPD2PI, + + IX86_BUILTIN_CVTPI2PD, + IX86_BUILTIN_CVTSI2SD, + IX86_BUILTIN_CVTSI642SD, + + IX86_BUILTIN_CVTSD2SI, + IX86_BUILTIN_CVTSD2SI64, + IX86_BUILTIN_CVTSD2SS, + IX86_BUILTIN_CVTSS2SD, + IX86_BUILTIN_CVTTSD2SI, + IX86_BUILTIN_CVTTSD2SI64, + + IX86_BUILTIN_CVTPS2DQ, + IX86_BUILTIN_CVTPS2PD, + IX86_BUILTIN_CVTTPS2DQ, + + IX86_BUILTIN_MOVNTI, + IX86_BUILTIN_MOVNTPD, + IX86_BUILTIN_MOVNTDQ, + + IX86_BUILTIN_SETPD1, + IX86_BUILTIN_SETPD, + IX86_BUILTIN_CLRPD, + IX86_BUILTIN_SETRPD, + IX86_BUILTIN_LOADPD1, + IX86_BUILTIN_LOADRPD, + IX86_BUILTIN_STOREPD1, + IX86_BUILTIN_STORERPD, + + /* SSE2 MMX */ + IX86_BUILTIN_MASKMOVDQU, + IX86_BUILTIN_MOVMSKPD, + IX86_BUILTIN_PMOVMSKB128, + IX86_BUILTIN_MOVQ2DQ, + IX86_BUILTIN_MOVDQ2Q, + + IX86_BUILTIN_PACKSSWB128, + IX86_BUILTIN_PACKSSDW128, + IX86_BUILTIN_PACKUSWB128, + + IX86_BUILTIN_PADDB128, + IX86_BUILTIN_PADDW128, + IX86_BUILTIN_PADDD128, + IX86_BUILTIN_PADDQ128, + IX86_BUILTIN_PADDSB128, + IX86_BUILTIN_PADDSW128, + IX86_BUILTIN_PADDUSB128, + IX86_BUILTIN_PADDUSW128, + IX86_BUILTIN_PSUBB128, + IX86_BUILTIN_PSUBW128, + IX86_BUILTIN_PSUBD128, + IX86_BUILTIN_PSUBQ128, + IX86_BUILTIN_PSUBSB128, + IX86_BUILTIN_PSUBSW128, + IX86_BUILTIN_PSUBUSB128, + IX86_BUILTIN_PSUBUSW128, + + IX86_BUILTIN_PAND128, + IX86_BUILTIN_PANDN128, + IX86_BUILTIN_POR128, + IX86_BUILTIN_PXOR128, + + IX86_BUILTIN_PAVGB128, + IX86_BUILTIN_PAVGW128, + + IX86_BUILTIN_PCMPEQB128, + IX86_BUILTIN_PCMPEQW128, + IX86_BUILTIN_PCMPEQD128, + IX86_BUILTIN_PCMPGTB128, + IX86_BUILTIN_PCMPGTW128, + IX86_BUILTIN_PCMPGTD128, + + IX86_BUILTIN_PEXTRW128, + IX86_BUILTIN_PINSRW128, + + IX86_BUILTIN_PMADDWD128, + + IX86_BUILTIN_PMAXSW128, + IX86_BUILTIN_PMAXUB128, + IX86_BUILTIN_PMINSW128, + IX86_BUILTIN_PMINUB128, + + IX86_BUILTIN_PMULUDQ, + IX86_BUILTIN_PMULUDQ128, + IX86_BUILTIN_PMULHUW128, + IX86_BUILTIN_PMULHW128, + IX86_BUILTIN_PMULLW128, + + IX86_BUILTIN_PSADBW128, + IX86_BUILTIN_PSHUFHW, + IX86_BUILTIN_PSHUFLW, + IX86_BUILTIN_PSHUFD, + + IX86_BUILTIN_PSLLW128, + IX86_BUILTIN_PSLLD128, + IX86_BUILTIN_PSLLQ128, + IX86_BUILTIN_PSRAW128, + IX86_BUILTIN_PSRAD128, + IX86_BUILTIN_PSRLW128, + IX86_BUILTIN_PSRLD128, + IX86_BUILTIN_PSRLQ128, + IX86_BUILTIN_PSLLDQI128, + IX86_BUILTIN_PSLLWI128, + IX86_BUILTIN_PSLLDI128, + IX86_BUILTIN_PSLLQI128, + IX86_BUILTIN_PSRAWI128, + IX86_BUILTIN_PSRADI128, + IX86_BUILTIN_PSRLDQI128, + IX86_BUILTIN_PSRLWI128, + IX86_BUILTIN_PSRLDI128, + IX86_BUILTIN_PSRLQI128, + + IX86_BUILTIN_PUNPCKHBW128, + IX86_BUILTIN_PUNPCKHWD128, + IX86_BUILTIN_PUNPCKHDQ128, + IX86_BUILTIN_PUNPCKHQDQ128, + IX86_BUILTIN_PUNPCKLBW128, + IX86_BUILTIN_PUNPCKLWD128, + IX86_BUILTIN_PUNPCKLDQ128, + IX86_BUILTIN_PUNPCKLQDQ128, + + IX86_BUILTIN_CLFLUSH, + IX86_BUILTIN_MFENCE, + IX86_BUILTIN_LFENCE, + + /* Prescott New Instructions. */ + IX86_BUILTIN_ADDSUBPS, + IX86_BUILTIN_HADDPS, + IX86_BUILTIN_HSUBPS, + IX86_BUILTIN_MOVSHDUP, + IX86_BUILTIN_MOVSLDUP, + IX86_BUILTIN_ADDSUBPD, + IX86_BUILTIN_HADDPD, + IX86_BUILTIN_HSUBPD, + IX86_BUILTIN_LOADDDUP, + IX86_BUILTIN_MOVDDUP, + IX86_BUILTIN_LDDQU, + + IX86_BUILTIN_MONITOR, + IX86_BUILTIN_MWAIT, + + IX86_BUILTIN_MAX +}; + /* Max number of args passed in registers. If this is more than 3, we will have problems with ebx (register #4), since it is a caller save register and is also used as the pic register in ELF. So for now, don't allow more than @@ -1742,6 +2568,12 @@ do { \ for the index in the tablejump instruction. */ #define CASE_VECTOR_MODE (!TARGET_64BIT || flag_pic ? SImode : DImode) +/* Define as C expression which evaluates to nonzero if the tablejump + instruction expects the table to contain offsets from the address of the + table. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE 1 */ + /* Define this as 1 if `char' should by default be signed; else as 0. */ #define DEFAULT_SIGNED_CHAR 1 @@ -1761,7 +2593,7 @@ do { \ #define MOVE_MAX_PIECES (TARGET_64BIT ? 8 : 4) /* If a memory-to-memory move would take MOVE_RATIO or more simple - move-instruction pairs, we will do a movmem or libcall instead. + move-instruction pairs, we will do a movstr or libcall instead. Increasing the value will always make code faster, but eventually incurs high cost in increased code size. @@ -1769,12 +2601,6 @@ do { \ #define MOVE_RATIO (optimize_size ? 3 : ix86_cost->move_ratio) -/* If a clear memory operation would take CLEAR_RATIO or more simple - move-instruction sequences, we will do a clrmem or libcall instead. */ - -#define CLEAR_RATIO (optimize_size ? 2 \ - : ix86_cost->move_ratio > 6 ? 6 : ix86_cost->move_ratio) - /* Define if shifts truncate the shift count which implies one can omit a sign-extension or zero-extension of a shift count. */ @@ -1786,6 +2612,11 @@ do { \ is done just by pretending it is already truncated. */ #define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 +/* When a prototype says `char' or `short', really pass an `int'. + (The 386 can't easily push less than an int.) */ + +#define PROMOTE_PROTOTYPES 1 + /* A macro to update M and UNSIGNEDP when an object whose type is TYPE and which has the specified mode and signedness is to be stored in a register. This macro is only called when TYPE is a @@ -1879,6 +2710,12 @@ do { \ faster than one with a register address. */ #define NO_FUNCTION_CSE + +/* Define this macro if it is as good or better for a function to call + itself with an explicit address than to call an address kept in a + register. */ + +#define NO_RECURSIVE_FUNCTION_CSE /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, return the mode to be used for the comparison. @@ -1898,7 +2735,9 @@ do { \ /* A C expression whose value is reversed condition code of the CODE for comparison done in CC_MODE mode. */ -#define REVERSE_CONDITION(CODE, MODE) ix86_reverse_condition ((CODE), (MODE)) +#define REVERSE_CONDITION(CODE, MODE) \ + ((MODE) != CCFPmode && (MODE) != CCFPUmode ? reverse_condition (CODE) \ + : reverse_condition_maybe_unordered (CODE)) /* Control the assembler format that we output, to the extent @@ -1907,7 +2746,7 @@ do { \ /* How to refer to registers in assembler output. This sequence is indexed by compiler's hard-register-number (see above). */ -/* In order to refer to the first 8 regs as 32 bit regs, prefix an "e". +/* In order to refer to the first 8 regs as 32 bit regs prefix an "e" For non floating point regs, the following are the HImode names. For float regs, the stack top is sometimes referred to as "%st(0)" @@ -1932,7 +2771,9 @@ do { \ { "rax", 0 }, { "rdx", 1 }, { "rcx", 2 }, { "rbx", 3 }, \ { "rsi", 4 }, { "rdi", 5 }, { "rbp", 6 }, { "rsp", 7 }, \ { "al", 0 }, { "dl", 1 }, { "cl", 2 }, { "bl", 3 }, \ - { "ah", 0 }, { "dh", 1 }, { "ch", 2 }, { "bh", 3 } } + { "ah", 0 }, { "dh", 1 }, { "ch", 2 }, { "bh", 3 }, \ + { "mm0", 8}, { "mm1", 9}, { "mm2", 10}, { "mm3", 11}, \ + { "mm4", 12}, { "mm5", 13}, { "mm6", 14}, { "mm7", 15} } /* Note we are omitting these since currently I don't know how to get gcc to use these, since they want the same but different @@ -1987,7 +2828,9 @@ extern int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER]; Whether or not a particular assembler allows us to enter such, I guess we'll have to see. */ #define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \ - asm_preferred_eh_data_format ((CODE), (GLOBAL)) + (flag_pic \ + ? ((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4\ + : DW_EH_PE_absptr) /* This is how to output an insn to push a register on the stack. It need not be very fast code. */ @@ -2023,13 +2866,24 @@ do { \ #define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ ix86_output_addr_diff_elt ((FILE), (VALUE), (REL)) -/* Under some conditions we need jump tables in the text section, - because the assembler cannot handle label differences between - sections. This is the case for x86_64 on Mach-O for example. */ +/* Under some conditions we need jump tables in the text section, because + the assembler cannot handle label differences between sections. */ #define JUMP_TABLES_IN_TEXT_SECTION \ - (flag_pic && ((TARGET_MACHO && TARGET_64BIT) \ - || (!TARGET_64BIT && !HAVE_AS_GOTOFF_IN_DATA))) + (!TARGET_64BIT && flag_pic && !HAVE_AS_GOTOFF_IN_DATA) + +/* A C statement that outputs an address constant appropriate to + for DWARF debugging. */ + +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE, X) \ + i386_dwarf_output_addr_const ((FILE), (X)) + +/* Emit a dtp-relative reference to a TLS variable. */ + +#ifdef HAVE_AS_TLS +#define ASM_OUTPUT_DWARF_DTPREL(FILE, SIZE, X) \ + i386_output_dwarf_dtprel (FILE, SIZE, X) +#endif /* Switch to init or fini section via SECTION_OP, emit a call to FUNC, and switch back. For x86 we do this only to save a few bytes that @@ -2066,6 +2920,95 @@ do { \ #define RET return "" #define AT_SP(MODE) (gen_rtx_MEM ((MODE), stack_pointer_rtx)) +/* Define the codes that are matched by predicates in i386.c. */ + +#define PREDICATE_CODES \ + {"x86_64_immediate_operand", {CONST_INT, SUBREG, REG, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_nonmemory_operand", {CONST_INT, SUBREG, REG, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_movabs_operand", {CONST_INT, SUBREG, REG, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_szext_nonmemory_operand", {CONST_INT, SUBREG, REG, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_general_operand", {CONST_INT, SUBREG, REG, MEM, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_szext_general_operand", {CONST_INT, SUBREG, REG, MEM, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_zext_immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, \ + SYMBOL_REF, LABEL_REF}}, \ + {"shiftdi_operand", {SUBREG, REG, MEM}}, \ + {"const_int_1_31_operand", {CONST_INT}}, \ + {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \ + {"aligned_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \ + LABEL_REF, SUBREG, REG, MEM}}, \ + {"pic_symbolic_operand", {CONST}}, \ + {"call_insn_operand", {REG, SUBREG, MEM, SYMBOL_REF}}, \ + {"sibcall_insn_operand", {REG, SUBREG, SYMBOL_REF}}, \ + {"constant_call_address_operand", {SYMBOL_REF, CONST}}, \ + {"const0_operand", {CONST_INT, CONST_DOUBLE}}, \ + {"const1_operand", {CONST_INT}}, \ + {"const248_operand", {CONST_INT}}, \ + {"const_0_to_3_operand", {CONST_INT}}, \ + {"const_0_to_7_operand", {CONST_INT}}, \ + {"const_0_to_15_operand", {CONST_INT}}, \ + {"const_0_to_255_operand", {CONST_INT}}, \ + {"incdec_operand", {CONST_INT}}, \ + {"mmx_reg_operand", {REG}}, \ + {"reg_no_sp_operand", {SUBREG, REG}}, \ + {"general_no_elim_operand", {CONST_INT, CONST_DOUBLE, CONST, \ + SYMBOL_REF, LABEL_REF, SUBREG, REG, MEM}}, \ + {"nonmemory_no_elim_operand", {CONST_INT, REG, SUBREG}}, \ + {"index_register_operand", {SUBREG, REG}}, \ + {"flags_reg_operand", {REG}}, \ + {"q_regs_operand", {SUBREG, REG}}, \ + {"non_q_regs_operand", {SUBREG, REG}}, \ + {"fcmov_comparison_operator", {EQ, NE, LTU, GTU, LEU, GEU, UNORDERED, \ + ORDERED, LT, UNLT, GT, UNGT, LE, UNLE, \ + GE, UNGE, LTGT, UNEQ}}, \ + {"sse_comparison_operator", {EQ, LT, LE, UNORDERED, NE, UNGE, UNGT, \ + ORDERED, UNEQ, UNLT, UNLE, LTGT, GE, GT \ + }}, \ + {"ix86_comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, \ + GTU, UNORDERED, ORDERED, UNLE, UNLT, \ + UNGE, UNGT, LTGT, UNEQ }}, \ + {"ix86_carry_flag_operator", {LTU, LT, UNLT, GT, UNGT, LE, UNLE, \ + GE, UNGE, LTGT, UNEQ}}, \ + {"cmp_fp_expander_operand", {CONST_DOUBLE, SUBREG, REG, MEM}}, \ + {"ext_register_operand", {SUBREG, REG}}, \ + {"binary_fp_operator", {PLUS, MINUS, MULT, DIV}}, \ + {"mult_operator", {MULT}}, \ + {"div_operator", {DIV}}, \ + {"arith_or_logical_operator", {PLUS, MULT, AND, IOR, XOR, SMIN, SMAX, \ + UMIN, UMAX, COMPARE, MINUS, DIV, MOD, \ + UDIV, UMOD, ASHIFT, ROTATE, ASHIFTRT, \ + LSHIFTRT, ROTATERT}}, \ + {"promotable_binary_operator", {PLUS, MULT, AND, IOR, XOR, ASHIFT}}, \ + {"memory_displacement_operand", {MEM}}, \ + {"cmpsi_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \ + LABEL_REF, SUBREG, REG, MEM, AND}}, \ + {"long_memory_operand", {MEM}}, \ + {"tls_symbolic_operand", {SYMBOL_REF}}, \ + {"global_dynamic_symbolic_operand", {SYMBOL_REF}}, \ + {"local_dynamic_symbolic_operand", {SYMBOL_REF}}, \ + {"initial_exec_symbolic_operand", {SYMBOL_REF}}, \ + {"local_exec_symbolic_operand", {SYMBOL_REF}}, \ + {"any_fp_register_operand", {REG}}, \ + {"register_and_not_any_fp_reg_operand", {REG}}, \ + {"fp_register_operand", {REG}}, \ + {"register_and_not_fp_reg_operand", {REG}}, \ + {"zero_extended_scalar_load_operand", {MEM}}, \ + {"vector_move_operand", {CONST_VECTOR, SUBREG, REG, MEM}}, \ + {"no_seg_address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \ + LABEL_REF, SUBREG, REG, MEM, PLUS, MULT}}, \ + {"compare_operator", {COMPARE}}, + +/* A list of predicates that do special things with modes, and so + should not elicit warnings for VOIDmode match_operand. */ + +#define SPECIAL_MODE_PREDICATES \ + "ext_register_operand", + /* Which processor to schedule for. The cpu attribute defines a list that mirrors this list, so changes to i386.md must be made at the same time. */ @@ -2079,14 +3022,14 @@ enum processor_type PROCESSOR_ATHLON, PROCESSOR_PENTIUM4, PROCESSOR_K8, - PROCESSOR_NOCONA, - PROCESSOR_GENERIC32, - PROCESSOR_GENERIC64, PROCESSOR_max }; extern enum processor_type ix86_tune; +extern const char *ix86_tune_string; + extern enum processor_type ix86_arch; +extern const char *ix86_arch_string; enum fpmath_unit { @@ -2095,15 +3038,16 @@ enum fpmath_unit }; extern enum fpmath_unit ix86_fpmath; +extern const char *ix86_fpmath_string; enum tls_dialect { TLS_DIALECT_GNU, - TLS_DIALECT_GNU2, TLS_DIALECT_SUN }; extern enum tls_dialect ix86_tls_dialect; +extern const char *ix86_tls_dialect_string; enum cmodel { CM_32, /* The traditional 32-bit ABI. */ @@ -2111,11 +3055,11 @@ enum cmodel { CM_KERNEL, /* Assumes all code and data fits in the high 31 bits. */ CM_MEDIUM, /* Assumes code fits in the low 31 bits; data unlimited. */ CM_LARGE, /* No assumptions. */ - CM_SMALL_PIC, /* Assumes code+data+got/plt fits in a 31 bit region. */ - CM_MEDIUM_PIC /* Assumes code+got/plt fits in a 31 bit region. */ + CM_SMALL_PIC /* Assumes code+data+got/plt fits in a 31 bit region. */ }; extern enum cmodel ix86_cmodel; +extern const char *ix86_cmodel_string; /* Size of the RED_ZONE area. */ #define RED_ZONE_SIZE 128 @@ -2127,16 +3071,31 @@ enum asm_dialect { ASM_INTEL }; +extern const char *ix86_asm_string; extern enum asm_dialect ix86_asm_dialect; -extern unsigned int ix86_preferred_stack_boundary; -extern int ix86_branch_cost, ix86_section_threshold; + +extern int ix86_regparm; +extern const char *ix86_regparm_string; + +extern int ix86_preferred_stack_boundary; +extern const char *ix86_preferred_stack_boundary_string; + +extern int ix86_branch_cost; +extern const char *ix86_branch_cost_string; + +extern const char *ix86_debug_arg_string; +extern const char *ix86_debug_addr_string; + +/* Obsoleted by -f options. Remove before 3.2 ships. */ +extern const char *ix86_align_loops_string; +extern const char *ix86_align_jumps_string; +extern const char *ix86_align_funcs_string; /* Smallest class containing REGNO. */ extern enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER]; extern rtx ix86_compare_op0; /* operand 0 for comparisons */ extern rtx ix86_compare_op1; /* operand 1 for comparisons */ -extern rtx ix86_compare_emitted; /* To properly truncate FP values into integers, we need to set i387 control word. We can't emit proper mode switching code before reload, as spills @@ -2153,31 +3112,12 @@ extern rtx ix86_compare_emitted; Post-reload pass may be later used to eliminate the redundant fildcw if needed. */ -enum ix86_entity -{ - I387_TRUNC = 0, - I387_FLOOR, - I387_CEIL, - I387_MASK_PM, - MAX_386_ENTITIES -}; - -enum ix86_stack_slot -{ - SLOT_TEMP = 0, - SLOT_CW_STORED, - SLOT_CW_TRUNC, - SLOT_CW_FLOOR, - SLOT_CW_CEIL, - SLOT_CW_MASK_PM, - MAX_386_STACK_LOCALS -}; +enum fp_cw_mode {FP_CW_STORED, FP_CW_UNINITIALIZED, FP_CW_ANY}; /* Define this macro if the port needs extra instructions inserted for mode switching in an optimizing compilation. */ -#define OPTIMIZE_MODE_SWITCHING(ENTITY) \ - ix86_optimize_mode_switching[(ENTITY)] +#define OPTIMIZE_MODE_SWITCHING(ENTITY) ix86_optimize_mode_switching /* If you define `OPTIMIZE_MODE_SWITCHING', you have to define this as initializer for an array of integers. Each initializer element N @@ -2187,16 +3127,22 @@ enum ix86_stack_slot starting counting at zero - determines the integer that is used to refer to the mode-switched entity in question. */ -#define NUM_MODES_FOR_MODE_SWITCHING \ - { I387_CW_ANY, I387_CW_ANY, I387_CW_ANY, I387_CW_ANY } +#define NUM_MODES_FOR_MODE_SWITCHING { FP_CW_ANY } /* ENTITY is an integer specifying a mode-switched entity. If `OPTIMIZE_MODE_SWITCHING' is defined, you must define this macro to return an integer value not larger than the corresponding element in `NUM_MODES_FOR_MODE_SWITCHING', to denote the mode that ENTITY - must be switched into prior to the execution of INSN. */ + must be switched into prior to the execution of INSN. */ -#define MODE_NEEDED(ENTITY, I) ix86_mode_needed ((ENTITY), (I)) +#define MODE_NEEDED(ENTITY, I) \ + (GET_CODE (I) == CALL_INSN \ + || (GET_CODE (I) == INSN && (asm_noperands (PATTERN (I)) >= 0 \ + || GET_CODE (PATTERN (I)) == ASM_INPUT))\ + ? FP_CW_UNINITIALIZED \ + : recog_memoized (I) < 0 || get_attr_type (I) != TYPE_FISTP \ + ? FP_CW_ANY \ + : FP_CW_STORED) /* This macro specifies the order in which modes for ENTITY are processed. 0 is the highest priority. */ @@ -2208,10 +3154,10 @@ enum ix86_stack_slot are to be inserted. */ #define EMIT_MODE_SET(ENTITY, MODE, HARD_REGS_LIVE) \ - ((MODE) != I387_CW_ANY && (MODE) != I387_CW_UNINITIALIZED \ - ? emit_i387_cw_initialization (MODE), 0 \ + ((MODE) == FP_CW_STORED \ + ? emit_i387_cw_initialization (assign_386_stack_local (HImode, 1), \ + assign_386_stack_local (HImode, 2)), 0\ : 0) - /* Avoid renaming of stack registers, as doing so in combination with scheduling just increases amount of live registers at time and in @@ -2231,49 +3177,25 @@ struct machine_function GTY(()) { struct stack_local_entry *stack_locals; const char *some_ld_name; - rtx force_align_arg_pointer; int save_varrargs_registers; int accesses_prev_frame; - int optimize_mode_switching[MAX_386_ENTITIES]; + int optimize_mode_switching; /* Set by ix86_compute_frame_layout and used by prologue/epilogue expander to determine the style used. */ int use_fast_prologue_epilogue; /* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE has been computed for. */ int use_fast_prologue_epilogue_nregs; - /* If true, the current function needs the default PIC register, not - an alternate register (on x86) and must not use the red zone (on - x86_64), even if it's a leaf function. We don't want the - function to be regarded as non-leaf because TLS calls need not - affect register allocation. This flag is set when a TLS call - instruction is expanded within a function, and never reset, even - if all such instructions are optimized away. Use the - ix86_current_function_calls_tls_descriptor macro for a better - approximation. */ - int tls_descriptor_call_expanded_p; }; #define ix86_stack_locals (cfun->machine->stack_locals) #define ix86_save_varrargs_registers (cfun->machine->save_varrargs_registers) #define ix86_optimize_mode_switching (cfun->machine->optimize_mode_switching) -#define ix86_tls_descriptor_calls_expanded_in_cfun \ - (cfun->machine->tls_descriptor_call_expanded_p) -/* Since tls_descriptor_call_expanded is not cleared, even if all TLS - calls are optimized away, we try to detect cases in which it was - optimized away. Since such instructions (use (reg REG_SP)), we can - verify whether there's any such instruction live by testing that - REG_SP is live. */ -#define ix86_current_function_calls_tls_descriptor \ - (ix86_tls_descriptor_calls_expanded_in_cfun && regs_ever_live[SP_REG]) /* Control behavior of x86_file_start. */ #define X86_FILE_START_VERSION_DIRECTIVE false #define X86_FILE_START_FLTUSED false -/* Flag to mark data that is in the large address area. */ -#define SYMBOL_FLAG_FAR_ADDR (SYMBOL_FLAG_MACH_DEP << 0) -#define SYMBOL_REF_FAR_ADDR_P(X) \ - ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_FAR_ADDR) != 0) /* Local variables: version-control: t diff --git a/contrib/gcc/config/i386/i386.md b/contrib/gcc/config/i386/i386.md index d24b32a..0fbe00b 100644 --- a/contrib/gcc/config/i386/i386.md +++ b/contrib/gcc/config/i386/i386.md @@ -1,6 +1,6 @@ ;; GCC machine description for IA-32 and x86-64. ;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -;; 2001, 2002, 2003, 2004, 2005, 2006 +;; 2001, 2002, 2003, 2004 ;; Free Software Foundation, Inc. ;; Mostly by William Schelter. ;; x86_64 support added by Jan Hubicka @@ -19,8 +19,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GCC; see the file COPYING. If not, write to -;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. */ +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. */ ;; ;; The original PO technology requires these to be ordered by speed, ;; so that assigner will pick the fastest. @@ -66,114 +66,76 @@ (UNSPEC_STACK_ALLOC 11) (UNSPEC_SET_GOT 12) (UNSPEC_SSE_PROLOGUE_SAVE 13) - (UNSPEC_REG_SAVE 14) - (UNSPEC_DEF_CFA 15) ; TLS support - (UNSPEC_TP 16) - (UNSPEC_TLS_GD 17) - (UNSPEC_TLS_LD_BASE 18) - (UNSPEC_TLSDESC 19) + (UNSPEC_TP 15) + (UNSPEC_TLS_GD 16) + (UNSPEC_TLS_LD_BASE 17) ; Other random patterns (UNSPEC_SCAS 20) - (UNSPEC_FNSTSW 21) - (UNSPEC_SAHF 22) - (UNSPEC_FSTCW 23) - (UNSPEC_ADD_CARRY 24) - (UNSPEC_FLDCW 25) - (UNSPEC_REP 26) - (UNSPEC_EH_RETURN 27) - (UNSPEC_LD_MPIC 28) ; load_macho_picbase + (UNSPEC_SIN 21) + (UNSPEC_COS 22) + (UNSPEC_FNSTSW 24) + (UNSPEC_SAHF 25) + (UNSPEC_FSTCW 26) + (UNSPEC_ADD_CARRY 27) + (UNSPEC_FLDCW 28) ; For SSE/MMX support: - (UNSPEC_FIX_NOTRUNC 30) - (UNSPEC_MASKMOV 31) - (UNSPEC_MOVMSK 32) - (UNSPEC_MOVNT 33) - (UNSPEC_MOVU 34) - (UNSPEC_RCP 35) - (UNSPEC_RSQRT 36) - (UNSPEC_SFENCE 37) - (UNSPEC_NOP 38) ; prevents combiner cleverness - (UNSPEC_PFRCP 39) - (UNSPEC_PFRCPIT1 40) - (UNSPEC_PFRCPIT2 41) - (UNSPEC_PFRSQRT 42) - (UNSPEC_PFRSQIT1 43) - (UNSPEC_MFENCE 44) - (UNSPEC_LFENCE 45) - (UNSPEC_PSADBW 46) - (UNSPEC_LDQQU 47) - - ; Generic math support - (UNSPEC_COPYSIGN 50) - (UNSPEC_IEEE_MIN 51) ; not commutative - (UNSPEC_IEEE_MAX 52) ; not commutative + (UNSPEC_FIX 30) + (UNSPEC_MASKMOV 32) + (UNSPEC_MOVMSK 33) + (UNSPEC_MOVNT 34) + (UNSPEC_MOVA 38) + (UNSPEC_MOVU 39) + (UNSPEC_SHUFFLE 41) + (UNSPEC_RCP 42) + (UNSPEC_RSQRT 43) + (UNSPEC_SFENCE 44) + (UNSPEC_NOP 45) ; prevents combiner cleverness + (UNSPEC_PAVGUSB 49) + (UNSPEC_PFRCP 50) + (UNSPEC_PFRCPIT1 51) + (UNSPEC_PFRCPIT2 52) + (UNSPEC_PFRSQRT 53) + (UNSPEC_PFRSQIT1 54) + (UNSPEC_PSHUFLW 55) + (UNSPEC_PSHUFHW 56) + (UNSPEC_MFENCE 59) + (UNSPEC_LFENCE 60) + (UNSPEC_PSADBW 61) + (UNSPEC_ADDSUB 71) + (UNSPEC_HADD 72) + (UNSPEC_HSUB 73) + (UNSPEC_MOVSHDUP 74) + (UNSPEC_MOVSLDUP 75) + (UNSPEC_LDQQU 76) + (UNSPEC_MOVDDUP 77) ; x87 Floating point - (UNSPEC_SIN 60) - (UNSPEC_COS 61) - (UNSPEC_FPATAN 62) - (UNSPEC_FYL2X 63) - (UNSPEC_FYL2XP1 64) - (UNSPEC_FRNDINT 65) - (UNSPEC_FIST 66) - (UNSPEC_F2XM1 67) - - ; x87 Rounding - (UNSPEC_FRNDINT_FLOOR 70) - (UNSPEC_FRNDINT_CEIL 71) - (UNSPEC_FRNDINT_TRUNC 72) - (UNSPEC_FRNDINT_MASK_PM 73) - (UNSPEC_FIST_FLOOR 74) - (UNSPEC_FIST_CEIL 75) - - ; x87 Double output FP - (UNSPEC_SINCOS_COS 80) - (UNSPEC_SINCOS_SIN 81) - (UNSPEC_TAN_ONE 82) - (UNSPEC_TAN_TAN 83) - (UNSPEC_XTRACT_FRACT 84) - (UNSPEC_XTRACT_EXP 85) - (UNSPEC_FSCALE_FRACT 86) - (UNSPEC_FSCALE_EXP 87) - (UNSPEC_FPREM_F 88) - (UNSPEC_FPREM_U 89) - (UNSPEC_FPREM1_F 90) - (UNSPEC_FPREM1_U 91) - - ; SSP patterns - (UNSPEC_SP_SET 100) - (UNSPEC_SP_TEST 101) - (UNSPEC_SP_TLS_SET 102) - (UNSPEC_SP_TLS_TEST 103) + (UNSPEC_FPATAN 65) + (UNSPEC_FYL2X 66) + (UNSPEC_FSCALE 67) + (UNSPEC_FRNDINT 68) + (UNSPEC_F2XM1 69) + + ; REP instruction + (UNSPEC_REP 75) ]) (define_constants [(UNSPECV_BLOCKAGE 0) - (UNSPECV_STACK_PROBE 1) - (UNSPECV_EMMS 2) - (UNSPECV_LDMXCSR 3) - (UNSPECV_STMXCSR 4) - (UNSPECV_FEMMS 5) - (UNSPECV_CLFLUSH 6) - (UNSPECV_ALIGN 7) - (UNSPECV_MONITOR 8) - (UNSPECV_MWAIT 9) - (UNSPECV_CMPXCHG_1 10) - (UNSPECV_CMPXCHG_2 11) - (UNSPECV_XCHG 12) - (UNSPECV_LOCK 13) - ]) - -;; Registers by name. -(define_constants - [(BP_REG 6) - (SP_REG 7) - (FLAGS_REG 17) - (FPSR_REG 18) - (DIRFLAG_REG 19) + (UNSPECV_STACK_PROBE 10) + (UNSPECV_EH_RETURN 13) + (UNSPECV_EMMS 31) + (UNSPECV_LDMXCSR 37) + (UNSPECV_STMXCSR 40) + (UNSPECV_FEMMS 46) + (UNSPECV_CLFLUSH 57) + (UNSPECV_ALIGN 68) + (UNSPECV_MONITOR 69) + (UNSPECV_MWAIT 70) ]) ;; Insns whose names begin with "x86_" are emitted by gen_FOO calls @@ -187,7 +149,7 @@ ;; Processor type. This attribute must exactly match the processor_type ;; enumeration in i386.h. -(define_attr "cpu" "i386,i486,pentium,pentiumpro,k6,athlon,pentium4,k8,nocona,generic32,generic64" +(define_attr "cpu" "i386,i486,pentium,pentiumpro,k6,athlon,pentium4,k8" (const (symbol_ref "ix86_tune"))) ;; A basic instruction type. Refinements due to arguments to be @@ -199,22 +161,22 @@ icmp,test,ibr,setcc,icmov, push,pop,call,callv,leave, str,cld, - fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp,fisttp,frndint, - sselog,sselog1,sseiadd,sseishft,sseimul, + fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp, + sselog,sseiadd,sseishft,sseimul, sse,ssemov,sseadd,ssemul,ssecmp,ssecomi,ssecvt,sseicvt,ssediv, mmx,mmxmov,mmxadd,mmxmul,mmxcmp,mmxcvt,mmxshft" (const_string "other")) ;; Main data type used by the insn (define_attr "mode" - "unknown,none,QI,HI,SI,DI,SF,DF,XF,TI,V4SF,V2DF,V2SF,V1DF" + "unknown,none,QI,HI,SI,DI,SF,DF,XF,TI,V4SF,V2DF,V2SF" (const_string "unknown")) ;; The CPU unit operations uses. (define_attr "unit" "integer,i387,sse,mmx,unknown" - (cond [(eq_attr "type" "fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp,fisttp,frndint") + (cond [(eq_attr "type" "fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp") (const_string "i387") - (eq_attr "type" "sselog,sselog1,sseiadd,sseishft,sseimul, + (eq_attr "type" "sselog,sseiadd,sseishft,sseimul, sse,ssemov,sseadd,ssemul,ssecmp,ssecomi,ssecvt,sseicvt,ssediv") (const_string "sse") (eq_attr "type" "mmx,mmxmov,mmxadd,mmxmul,mmxcmp,mmxcvt,mmxshft") @@ -248,7 +210,7 @@ (const_int 1) ] (symbol_ref "/* Update immediate_length and other attributes! */ - gcc_unreachable (),1"))) + abort(),1"))) ;; The (bounding maximum) length of an instruction address. (define_attr "length_address" "" @@ -284,7 +246,7 @@ (const_int 1) (const_int 0))) -;; Set when REX opcode prefix is used. +;; Set when 0f opcode prefix is used. (define_attr "prefix_rex" "" (cond [(and (eq_attr "mode" "DI") (eq_attr "type" "!push,pop,call,callv,leave,ibr")) @@ -316,12 +278,8 @@ (not (match_operand 0 "memory_operand" ""))) (const_int 0) (and (eq_attr "type" "imov") - (ior (and (match_operand 0 "register_operand" "") - (match_operand 1 "immediate_operand" "")) - (ior (and (match_operand 0 "ax_reg_operand" "") - (match_operand 1 "memory_displacement_only_operand" "")) - (and (match_operand 0 "memory_displacement_only_operand" "") - (match_operand 1 "ax_reg_operand" ""))))) + (and (match_operand 0 "register_operand" "") + (match_operand 1 "immediate_operand" ""))) (const_int 0) (and (eq_attr "type" "call") (match_operand 0 "constant_call_address_operand" "")) @@ -333,11 +291,10 @@ (const_int 1))) ;; The (bounding maximum) length of an instruction in bytes. -;; ??? fistp and frndint are in fact fldcw/{fistp,frndint}/fldcw sequences. -;; Later we may want to split them and compute proper length as for -;; other insns. +;; ??? fistp is in fact fldcw/fistp/fldcw sequence. Later we may want +;; to split it and compute proper length as for other insns. (define_attr "length" "" - (cond [(eq_attr "type" "other,multi,fistp,frndint") + (cond [(eq_attr "type" "other,multi,fistp") (const_int 16) (eq_attr "type" "fcmp") (const_int 4) @@ -365,8 +322,6 @@ (const_string "none") (eq_attr "type" "fistp,leave") (const_string "both") - (eq_attr "type" "frndint") - (const_string "load") (eq_attr "type" "push") (if_then_else (match_operand 1 "memory_operand" "") (const_string "both") @@ -396,7 +351,7 @@ (if_then_else (match_operand 1 "constant_call_address_operand" "") (const_string "none") (const_string "load")) - (and (eq_attr "type" "alu1,negnot,ishift1,sselog1") + (and (eq_attr "type" "alu1,negnot,ishift1") (match_operand 1 "memory_operand" "")) (const_string "both") (and (match_operand 0 "memory_operand" "") @@ -410,7 +365,7 @@ "!alu1,negnot,ishift1, imov,imovx,icmp,test, fmov,fcmp,fsgn, - sse,ssemov,ssecmp,ssecomi,ssecvt,sseicvt,sselog1, + sse,ssemov,ssecmp,ssecomi,ssecvt,sseicvt, mmx,mmxmov,mmxcmp,mmxcvt") (match_operand 2 "memory_operand" "")) (const_string "load") @@ -441,45 +396,15 @@ (define_attr "fp_int_src" "false,true" (const_string "false")) -;; Defines rounding mode of an FP operation. - -(define_attr "i387_cw" "trunc,floor,ceil,mask_pm,uninitialized,any" - (const_string "any")) - ;; Describe a user's asm statement. (define_asm_attributes [(set_attr "length" "128") (set_attr "type" "multi")]) - -;; All x87 floating point modes -(define_mode_macro X87MODEF [SF DF XF]) - -;; All integer modes handled by x87 fisttp operator. -(define_mode_macro X87MODEI [HI SI DI]) - -;; All integer modes handled by integer x87 operators. -(define_mode_macro X87MODEI12 [HI SI]) - -;; All SSE floating point modes -(define_mode_macro SSEMODEF [SF DF]) - -;; All integer modes handled by SSE cvtts?2si* operators. -(define_mode_macro SSEMODEI24 [SI DI]) - -;; Scheduling descriptions - (include "pentium.md") (include "ppro.md") (include "k6.md") (include "athlon.md") - - -;; Operand and operator predicates and constraints - -(include "predicates.md") -(include "constraints.md") - ;; Compare instructions. @@ -487,21 +412,8 @@ ;; actually generating RTL. The bCOND or sCOND (emitted immediately ;; after the cmp) will actually emit the cmpM. -(define_expand "cmpti" - [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:TI 0 "nonimmediate_operand" "") - (match_operand:TI 1 "x86_64_general_operand" "")))] - "TARGET_64BIT" -{ - if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) - operands[0] = force_reg (TImode, operands[0]); - ix86_compare_op0 = operands[0]; - ix86_compare_op1 = operands[1]; - DONE; -}) - (define_expand "cmpdi" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (compare:CC (match_operand:DI 0 "nonimmediate_operand" "") (match_operand:DI 1 "x86_64_general_operand" "")))] "" @@ -514,7 +426,7 @@ }) (define_expand "cmpsi" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (compare:CC (match_operand:SI 0 "cmpsi_operand" "") (match_operand:SI 1 "general_operand" "")))] "" @@ -527,7 +439,7 @@ }) (define_expand "cmphi" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (compare:CC (match_operand:HI 0 "nonimmediate_operand" "") (match_operand:HI 1 "general_operand" "")))] "" @@ -540,7 +452,7 @@ }) (define_expand "cmpqi" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (compare:CC (match_operand:QI 0 "nonimmediate_operand" "") (match_operand:QI 1 "general_operand" "")))] "TARGET_QIMODE_MATH" @@ -553,7 +465,7 @@ }) (define_insn "cmpdi_ccno_1_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:DI 0 "nonimmediate_operand" "r,?mr") (match_operand:DI 1 "const0_operand" "n,n")))] "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" @@ -565,7 +477,7 @@ (set_attr "mode" "DI")]) (define_insn "*cmpdi_minus_1_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (minus:DI (match_operand:DI 0 "nonimmediate_operand" "rm,r") (match_operand:DI 1 "x86_64_general_operand" "re,mr")) (const_int 0)))] @@ -575,14 +487,14 @@ (set_attr "mode" "DI")]) (define_expand "cmpdi_1_rex64" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (compare:CC (match_operand:DI 0 "nonimmediate_operand" "") (match_operand:DI 1 "general_operand" "")))] "TARGET_64BIT" "") (define_insn "cmpdi_1_insn_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:DI 0 "nonimmediate_operand" "mr,r") (match_operand:DI 1 "x86_64_general_operand" "re,mr")))] "TARGET_64BIT && ix86_match_ccmode (insn, CCmode)" @@ -592,7 +504,7 @@ (define_insn "*cmpsi_ccno_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:SI 0 "nonimmediate_operand" "r,?mr") (match_operand:SI 1 "const0_operand" "n,n")))] "ix86_match_ccmode (insn, CCNOmode)" @@ -604,7 +516,7 @@ (set_attr "mode" "SI")]) (define_insn "*cmpsi_minus_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (minus:SI (match_operand:SI 0 "nonimmediate_operand" "rm,r") (match_operand:SI 1 "general_operand" "ri,mr")) (const_int 0)))] @@ -614,14 +526,14 @@ (set_attr "mode" "SI")]) (define_expand "cmpsi_1" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (compare:CC (match_operand:SI 0 "nonimmediate_operand" "rm,r") (match_operand:SI 1 "general_operand" "ri,mr")))] "" "") (define_insn "*cmpsi_1_insn" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:SI 0 "nonimmediate_operand" "rm,r") (match_operand:SI 1 "general_operand" "ri,mr")))] "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) @@ -631,7 +543,7 @@ (set_attr "mode" "SI")]) (define_insn "*cmphi_ccno_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:HI 0 "nonimmediate_operand" "r,?mr") (match_operand:HI 1 "const0_operand" "n,n")))] "ix86_match_ccmode (insn, CCNOmode)" @@ -643,7 +555,7 @@ (set_attr "mode" "HI")]) (define_insn "*cmphi_minus_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (minus:HI (match_operand:HI 0 "nonimmediate_operand" "rm,r") (match_operand:HI 1 "general_operand" "ri,mr")) (const_int 0)))] @@ -653,7 +565,7 @@ (set_attr "mode" "HI")]) (define_insn "*cmphi_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:HI 0 "nonimmediate_operand" "rm,r") (match_operand:HI 1 "general_operand" "ri,mr")))] "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) @@ -663,7 +575,7 @@ (set_attr "mode" "HI")]) (define_insn "*cmpqi_ccno_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:QI 0 "nonimmediate_operand" "q,?mq") (match_operand:QI 1 "const0_operand" "n,n")))] "ix86_match_ccmode (insn, CCNOmode)" @@ -675,7 +587,7 @@ (set_attr "mode" "QI")]) (define_insn "*cmpqi_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:QI 0 "nonimmediate_operand" "qm,q") (match_operand:QI 1 "general_operand" "qi,mq")))] "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) @@ -685,7 +597,7 @@ (set_attr "mode" "QI")]) (define_insn "*cmpqi_minus_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (minus:QI (match_operand:QI 0 "nonimmediate_operand" "qm,q") (match_operand:QI 1 "general_operand" "qi,mq")) (const_int 0)))] @@ -695,7 +607,7 @@ (set_attr "mode" "QI")]) (define_insn "*cmpqi_ext_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:QI 0 "general_operand" "Qm") (subreg:QI @@ -709,7 +621,7 @@ (set_attr "mode" "QI")]) (define_insn "*cmpqi_ext_1_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:QI 0 "register_operand" "Q") (subreg:QI @@ -723,7 +635,7 @@ (set_attr "mode" "QI")]) (define_insn "*cmpqi_ext_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (subreg:QI (zero_extract:SI @@ -738,7 +650,7 @@ (set_attr "mode" "QI")]) (define_expand "cmpqi_ext_3" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (compare:CC (subreg:QI (zero_extract:SI @@ -750,7 +662,7 @@ "") (define_insn "cmpqi_ext_3_insn" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (subreg:QI (zero_extract:SI @@ -764,7 +676,7 @@ (set_attr "mode" "QI")]) (define_insn "cmpqi_ext_3_insn_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (subreg:QI (zero_extract:SI @@ -778,7 +690,7 @@ (set_attr "mode" "QI")]) (define_insn "*cmpqi_ext_4" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (subreg:QI (zero_extract:SI @@ -801,9 +713,9 @@ ;; the old patterns did, but with many more of them. (define_expand "cmpxf" - [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:XF 0 "nonmemory_operand" "") - (match_operand:XF 1 "nonmemory_operand" "")))] + [(set (reg:CC 17) + (compare:CC (match_operand:XF 0 "cmp_fp_expander_operand" "") + (match_operand:XF 1 "cmp_fp_expander_operand" "")))] "TARGET_80387" { ix86_compare_op0 = operands[0]; @@ -812,10 +724,10 @@ }) (define_expand "cmpdf" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (compare:CC (match_operand:DF 0 "cmp_fp_expander_operand" "") (match_operand:DF 1 "cmp_fp_expander_operand" "")))] - "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" + "TARGET_80387 || TARGET_SSE2" { ix86_compare_op0 = operands[0]; ix86_compare_op1 = operands[1]; @@ -823,10 +735,10 @@ }) (define_expand "cmpsf" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (compare:CC (match_operand:SF 0 "cmp_fp_expander_operand" "") (match_operand:SF 1 "cmp_fp_expander_operand" "")))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_80387 || TARGET_SSE" { ix86_compare_op0 = operands[0]; ix86_compare_op1 = operands[1]; @@ -839,22 +751,34 @@ ;; CCFPmode compare with exceptions ;; CCFPUmode compare with no exceptions -;; We may not use "#" to split and emit these, since the REG_DEAD notes -;; used to manage the reg stack popping would not be preserved. +;; %%% It is an unfortunate fact that ftst has no non-popping variant, +;; and that fp moves clobber the condition codes, and that there is +;; currently no way to describe this fact to reg-stack. So there are +;; no splitters yet for this. + +;; %%% YIKES! This scheme does not retain a strong connection between +;; the real compare and the ultimate cc0 user, so CC_REVERSE does not +;; work! Only allow tos/mem with tos in op 0. +;; +;; Hmm, of course, this is what the actual _hardware_ does. Perhaps +;; things aren't as bad as they sound... (define_insn "*cmpfp_0" [(set (match_operand:HI 0 "register_operand" "=a") (unspec:HI - [(compare:CCFP - (match_operand 1 "register_operand" "f") - (match_operand 2 "const0_operand" "X"))] - UNSPEC_FNSTSW))] + [(compare:CCFP (match_operand 1 "register_operand" "f") + (match_operand 2 "const0_operand" "X"))] + UNSPEC_FNSTSW))] "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) && GET_MODE (operands[1]) == GET_MODE (operands[2])" - "* return output_fp_compare (insn, operands, 0, 0);" +{ + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "ftst\;fnstsw\t%0\;fstp\t%y0"; + else + return "ftst\;fnstsw\t%0"; +} [(set_attr "type" "multi") - (set_attr "unit" "i387") (set (attr "mode") (cond [(match_operand:SF 1 "" "") (const_string "SF") @@ -863,7 +787,20 @@ ] (const_string "XF")))]) -(define_insn "*cmpfp_sf" +;; We may not use "#" to split and emit these, since the REG_DEAD notes +;; used to manage the reg stack popping would not be preserved. + +(define_insn "*cmpfp_2_sf" + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand:SF 0 "register_operand" "f") + (match_operand:SF 1 "nonimmediate_operand" "fm")))] + "TARGET_80387" + "* return output_fp_compare (insn, operands, 0, 0);" + [(set_attr "type" "fcmp") + (set_attr "mode" "SF")]) + +(define_insn "*cmpfp_2_sf_1" [(set (match_operand:HI 0 "register_operand" "=a") (unspec:HI [(compare:CCFP @@ -871,12 +808,21 @@ (match_operand:SF 2 "nonimmediate_operand" "fm"))] UNSPEC_FNSTSW))] "TARGET_80387" - "* return output_fp_compare (insn, operands, 0, 0);" - [(set_attr "type" "multi") - (set_attr "unit" "i387") + "* return output_fp_compare (insn, operands, 2, 0);" + [(set_attr "type" "fcmp") (set_attr "mode" "SF")]) -(define_insn "*cmpfp_df" +(define_insn "*cmpfp_2_df" + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "nonimmediate_operand" "fm")))] + "TARGET_80387" + "* return output_fp_compare (insn, operands, 0, 0);" + [(set_attr "type" "fcmp") + (set_attr "mode" "DF")]) + +(define_insn "*cmpfp_2_df_1" [(set (match_operand:HI 0 "register_operand" "=a") (unspec:HI [(compare:CCFP @@ -884,12 +830,21 @@ (match_operand:DF 2 "nonimmediate_operand" "fm"))] UNSPEC_FNSTSW))] "TARGET_80387" - "* return output_fp_compare (insn, operands, 0, 0);" + "* return output_fp_compare (insn, operands, 2, 0);" [(set_attr "type" "multi") - (set_attr "unit" "i387") (set_attr "mode" "DF")]) -(define_insn "*cmpfp_xf" +(define_insn "*cmpfp_2_xf" + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand:XF 0 "register_operand" "f") + (match_operand:XF 1 "register_operand" "f")))] + "TARGET_80387" + "* return output_fp_compare (insn, operands, 0, 0);" + [(set_attr "type" "fcmp") + (set_attr "mode" "XF")]) + +(define_insn "*cmpfp_2_xf_1" [(set (match_operand:HI 0 "register_operand" "=a") (unspec:HI [(compare:CCFP @@ -897,12 +852,29 @@ (match_operand:XF 2 "register_operand" "f"))] UNSPEC_FNSTSW))] "TARGET_80387" - "* return output_fp_compare (insn, operands, 0, 0);" + "* return output_fp_compare (insn, operands, 2, 0);" [(set_attr "type" "multi") - (set_attr "unit" "i387") (set_attr "mode" "XF")]) -(define_insn "*cmpfp_u" +(define_insn "*cmpfp_2u" + [(set (reg:CCFPU 18) + (compare:CCFPU + (match_operand 0 "register_operand" "f") + (match_operand 1 "register_operand" "f")))] + "TARGET_80387 + && FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (operands[0]) == GET_MODE (operands[1])" + "* return output_fp_compare (insn, operands, 0, 1);" + [(set_attr "type" "fcmp") + (set (attr "mode") + (cond [(match_operand:SF 1 "" "") + (const_string "SF") + (match_operand:DF 1 "" "") + (const_string "DF") + ] + (const_string "XF")))]) + +(define_insn "*cmpfp_2u_1" [(set (match_operand:HI 0 "register_operand" "=a") (unspec:HI [(compare:CCFPU @@ -912,9 +884,8 @@ "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) && GET_MODE (operands[1]) == GET_MODE (operands[2])" - "* return output_fp_compare (insn, operands, 0, 1);" + "* return output_fp_compare (insn, operands, 2, 1);" [(set_attr "type" "multi") - (set_attr "unit" "i387") (set (attr "mode") (cond [(match_operand:SF 1 "" "") (const_string "SF") @@ -923,56 +894,95 @@ ] (const_string "XF")))]) -(define_insn "*cmpfp_<mode>" - [(set (match_operand:HI 0 "register_operand" "=a") - (unspec:HI - [(compare:CCFP - (match_operand 1 "register_operand" "f") - (match_operator 3 "float_operator" - [(match_operand:X87MODEI12 2 "memory_operand" "m")]))] - UNSPEC_FNSTSW))] - "TARGET_80387 && TARGET_USE_<MODE>MODE_FIOP - && FLOAT_MODE_P (GET_MODE (operands[1])) - && (GET_MODE (operands [3]) == GET_MODE (operands[1]))" - "* return output_fp_compare (insn, operands, 0, 0);" - [(set_attr "type" "multi") - (set_attr "unit" "i387") - (set_attr "fp_int_src" "true") - (set_attr "mode" "<MODE>")]) +;; Patterns to match the SImode-in-memory ficom instructions. +;; +;; %%% Play games with accepting gp registers, as otherwise we have to +;; force them to memory during rtl generation, which is no good. We +;; can get rid of this once we teach reload to do memory input reloads +;; via pushes. + +(define_insn "*ficom_1" + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand 0 "register_operand" "f,f") + (float (match_operand:SI 1 "nonimmediate_operand" "m,?r"))))] + "0 && TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == GET_MODE (operands[0])" + "#") + +;; Split the not-really-implemented gp register case into a +;; push-op-pop sequence. +;; +;; %%% This is most efficient, but am I gonna get in trouble +;; for separating cc0_setter and cc0_user? + +(define_split + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand:SF 0 "register_operand" "") + (float (match_operand:SI 1 "register_operand" ""))))] + "0 && TARGET_80387 && reload_completed" + [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1)) + (set (reg:CCFP 18) (compare:CCFP (match_dup 0) (match_dup 2))) + (parallel [(set (match_dup 1) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] + "operands[2] = gen_rtx_MEM (Pmode, stack_pointer_rtx); + operands[2] = gen_rtx_FLOAT (GET_MODE (operands[0]), operands[2]);") ;; FP compares, step 2 ;; Move the fpsw to ax. -(define_insn "x86_fnstsw_1" +(define_insn "*x86_fnstsw_1" [(set (match_operand:HI 0 "register_operand" "=a") - (unspec:HI [(reg:CCFP FPSR_REG)] UNSPEC_FNSTSW))] + (unspec:HI [(reg 18)] UNSPEC_FNSTSW))] "TARGET_80387" "fnstsw\t%0" [(set_attr "length" "2") (set_attr "mode" "SI") - (set_attr "unit" "i387")]) + (set_attr "unit" "i387") + (set_attr "ppro_uops" "few")]) ;; FP compares, step 3 ;; Get ax into flags, general case. (define_insn "x86_sahf_1" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (unspec:CC [(match_operand:HI 0 "register_operand" "a")] UNSPEC_SAHF))] "!TARGET_64BIT" "sahf" [(set_attr "length" "1") (set_attr "athlon_decode" "vector") - (set_attr "mode" "SI")]) + (set_attr "mode" "SI") + (set_attr "ppro_uops" "one")]) ;; Pentium Pro can do steps 1 through 3 in one go. -(define_insn "*cmpfp_i_mixed" - [(set (reg:CCFP FLAGS_REG) - (compare:CCFP (match_operand 0 "register_operand" "f,x") - (match_operand 1 "nonimmediate_operand" "f,xm")))] - "TARGET_MIX_SSE_I387 +(define_insn "*cmpfp_i" + [(set (reg:CCFP 17) + (compare:CCFP (match_operand 0 "register_operand" "f") + (match_operand 1 "register_operand" "f")))] + "TARGET_80387 && TARGET_CMOVE + && !SSE_FLOAT_MODE_P (GET_MODE (operands[0])) + && FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (operands[0]) == GET_MODE (operands[0])" + "* return output_fp_compare (insn, operands, 1, 0);" + [(set_attr "type" "fcmp") + (set (attr "mode") + (cond [(match_operand:SF 1 "" "") + (const_string "SF") + (match_operand:DF 1 "" "") + (const_string "DF") + ] + (const_string "XF"))) + (set_attr "athlon_decode" "vector")]) + +(define_insn "*cmpfp_i_sse" + [(set (reg:CCFP 17) + (compare:CCFP (match_operand 0 "register_operand" "f#x,x#f") + (match_operand 1 "nonimmediate_operand" "f#x,xm#f")))] + "TARGET_80387 && SSE_FLOAT_MODE_P (GET_MODE (operands[0])) - && GET_MODE (operands[0]) == GET_MODE (operands[1])" + && GET_MODE (operands[0]) == GET_MODE (operands[0])" "* return output_fp_compare (insn, operands, 1, 0);" [(set_attr "type" "fcmp,ssecomi") (set (attr "mode") @@ -981,13 +991,12 @@ (const_string "DF"))) (set_attr "athlon_decode" "vector")]) -(define_insn "*cmpfp_i_sse" - [(set (reg:CCFP FLAGS_REG) +(define_insn "*cmpfp_i_sse_only" + [(set (reg:CCFP 17) (compare:CCFP (match_operand 0 "register_operand" "x") (match_operand 1 "nonimmediate_operand" "xm")))] - "TARGET_SSE_MATH - && SSE_FLOAT_MODE_P (GET_MODE (operands[0])) - && GET_MODE (operands[0]) == GET_MODE (operands[1])" + "SSE_FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (operands[0]) == GET_MODE (operands[0])" "* return output_fp_compare (insn, operands, 1, 0);" [(set_attr "type" "ssecomi") (set (attr "mode") @@ -996,15 +1005,15 @@ (const_string "DF"))) (set_attr "athlon_decode" "vector")]) -(define_insn "*cmpfp_i_i387" - [(set (reg:CCFP FLAGS_REG) - (compare:CCFP (match_operand 0 "register_operand" "f") - (match_operand 1 "register_operand" "f")))] +(define_insn "*cmpfp_iu" + [(set (reg:CCFPU 17) + (compare:CCFPU (match_operand 0 "register_operand" "f") + (match_operand 1 "register_operand" "f")))] "TARGET_80387 && TARGET_CMOVE - && (!TARGET_SSE_MATH || !SSE_FLOAT_MODE_P (GET_MODE (operands[0]))) + && !SSE_FLOAT_MODE_P (GET_MODE (operands[0])) && FLOAT_MODE_P (GET_MODE (operands[0])) && GET_MODE (operands[0]) == GET_MODE (operands[1])" - "* return output_fp_compare (insn, operands, 1, 0);" + "* return output_fp_compare (insn, operands, 1, 1);" [(set_attr "type" "fcmp") (set (attr "mode") (cond [(match_operand:SF 1 "" "") @@ -1015,11 +1024,11 @@ (const_string "XF"))) (set_attr "athlon_decode" "vector")]) -(define_insn "*cmpfp_iu_mixed" - [(set (reg:CCFPU FLAGS_REG) - (compare:CCFPU (match_operand 0 "register_operand" "f,x") - (match_operand 1 "nonimmediate_operand" "f,xm")))] - "TARGET_MIX_SSE_I387 +(define_insn "*cmpfp_iu_sse" + [(set (reg:CCFPU 17) + (compare:CCFPU (match_operand 0 "register_operand" "f#x,x#f") + (match_operand 1 "nonimmediate_operand" "f#x,xm#f")))] + "TARGET_80387 && SSE_FLOAT_MODE_P (GET_MODE (operands[0])) && GET_MODE (operands[0]) == GET_MODE (operands[1])" "* return output_fp_compare (insn, operands, 1, 1);" @@ -1030,12 +1039,11 @@ (const_string "DF"))) (set_attr "athlon_decode" "vector")]) -(define_insn "*cmpfp_iu_sse" - [(set (reg:CCFPU FLAGS_REG) +(define_insn "*cmpfp_iu_sse_only" + [(set (reg:CCFPU 17) (compare:CCFPU (match_operand 0 "register_operand" "x") (match_operand 1 "nonimmediate_operand" "xm")))] - "TARGET_SSE_MATH - && SSE_FLOAT_MODE_P (GET_MODE (operands[0])) + "SSE_FLOAT_MODE_P (GET_MODE (operands[0])) && GET_MODE (operands[0]) == GET_MODE (operands[1])" "* return output_fp_compare (insn, operands, 1, 1);" [(set_attr "type" "ssecomi") @@ -1044,25 +1052,6 @@ (const_string "SF") (const_string "DF"))) (set_attr "athlon_decode" "vector")]) - -(define_insn "*cmpfp_iu_387" - [(set (reg:CCFPU FLAGS_REG) - (compare:CCFPU (match_operand 0 "register_operand" "f") - (match_operand 1 "register_operand" "f")))] - "TARGET_80387 && TARGET_CMOVE - && (!TARGET_SSE_MATH || !SSE_FLOAT_MODE_P (GET_MODE (operands[0]))) - && FLOAT_MODE_P (GET_MODE (operands[0])) - && GET_MODE (operands[0]) == GET_MODE (operands[1])" - "* return output_fp_compare (insn, operands, 1, 1);" - [(set_attr "type" "fcmp") - (set (attr "mode") - (cond [(match_operand:SF 1 "" "") - (const_string "SF") - (match_operand:DF 1 "" "") - (const_string "DF") - ] - (const_string "XF"))) - (set_attr "athlon_decode" "vector")]) ;; Move instructions. @@ -1111,9 +1100,9 @@ (define_insn "*popsi1_epilogue" [(set (match_operand:SI 0 "nonimmediate_operand" "=r*m") - (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) - (plus:SI (reg:SI SP_REG) (const_int 4))) + (mem:SI (reg:SI 7))) + (set (reg:SI 7) + (plus:SI (reg:SI 7) (const_int 4))) (clobber (mem:BLK (scratch)))] "!TARGET_64BIT" "pop{l}\t%0" @@ -1122,9 +1111,9 @@ (define_insn "popsi1" [(set (match_operand:SI 0 "nonimmediate_operand" "=r*m") - (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) - (plus:SI (reg:SI SP_REG) (const_int 4)))] + (mem:SI (reg:SI 7))) + (set (reg:SI 7) + (plus:SI (reg:SI 7) (const_int 4)))] "!TARGET_64BIT" "pop{l}\t%0" [(set_attr "type" "pop") @@ -1133,7 +1122,7 @@ (define_insn "*movsi_xor" [(set (match_operand:SI 0 "register_operand" "=r") (match_operand:SI 1 "const0_operand" "i")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && (!TARGET_USE_MOV0 || optimize_size)" "xor{l}\t{%0, %0|%0, %0}" [(set_attr "type" "alu1") @@ -1143,7 +1132,7 @@ (define_insn "*movsi_or" [(set (match_operand:SI 0 "register_operand" "=r") (match_operand:SI 1 "immediate_operand" "i")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && operands[1] == constm1_rtx && (TARGET_PENTIUM || optimize_size)" @@ -1156,36 +1145,56 @@ (set_attr "length_immediate" "1")]) (define_insn "*movsi_1" - [(set (match_operand:SI 0 "nonimmediate_operand" - "=r ,m ,*y,*y,?rm,?*y,*x,*x,?r,m ,?*Y,*x") - (match_operand:SI 1 "general_operand" - "rinm,rin,C ,*y,*y ,rm ,C ,*x,*Y,*x,r ,m "))] - "!(MEM_P (operands[0]) && MEM_P (operands[1]))" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m,!*y,!rm,!*y,!*Y,!rm,!*Y") + (match_operand:SI 1 "general_operand" "rinm,rin,*y,*y,rm,*Y,*Y,rm"))] + "(TARGET_INTER_UNIT_MOVES || optimize_size) + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" { switch (get_attr_type (insn)) { - case TYPE_SSELOG1: + case TYPE_SSEMOV: if (get_attr_mode (insn) == MODE_TI) - return "pxor\t%0, %0"; - return "xorps\t%0, %0"; + return "movdqa\t{%1, %0|%0, %1}"; + return "movd\t{%1, %0|%0, %1}"; - case TYPE_SSEMOV: - switch (get_attr_mode (insn)) - { - case MODE_TI: - return "movdqa\t{%1, %0|%0, %1}"; - case MODE_V4SF: - return "movaps\t{%1, %0|%0, %1}"; - case MODE_SI: - return "movd\t{%1, %0|%0, %1}"; - case MODE_SF: - return "movss\t{%1, %0|%0, %1}"; - default: - gcc_unreachable (); - } + case TYPE_MMXMOV: + if (get_attr_mode (insn) == MODE_DI) + return "movq\t{%1, %0|%0, %1}"; + return "movd\t{%1, %0|%0, %1}"; - case TYPE_MMXADD: - return "pxor\t%0, %0"; + case TYPE_LEA: + return "lea{l}\t{%1, %0|%0, %1}"; + + default: + if (flag_pic && !LEGITIMATE_PIC_OPERAND_P (operands[1])) + abort(); + return "mov{l}\t{%1, %0|%0, %1}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "2,3,4") + (const_string "mmxmov") + (eq_attr "alternative" "5,6,7") + (const_string "ssemov") + (and (ne (symbol_ref "flag_pic") (const_int 0)) + (match_operand:SI 1 "symbolic_operand" "")) + (const_string "lea") + ] + (const_string "imov"))) + (set_attr "mode" "SI,SI,DI,SI,SI,TI,SI,SI")]) + +(define_insn "*movsi_1_nointernunit" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m,!*y,!m,!*y,!*Y,!m,!*Y") + (match_operand:SI 1 "general_operand" "rinm,rin,*y,*y,m,*Y,*Y,m"))] + "(!TARGET_INTER_UNIT_MOVES && !optimize_size) + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (get_attr_type (insn)) + { + case TYPE_SSEMOV: + if (get_attr_mode (insn) == MODE_TI) + return "movdqa\t{%1, %0|%0, %1}"; + return "movd\t{%1, %0|%0, %1}"; case TYPE_MMXMOV: if (get_attr_mode (insn) == MODE_DI) @@ -1196,36 +1205,22 @@ return "lea{l}\t{%1, %0|%0, %1}"; default: - gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1])); + if (flag_pic && !LEGITIMATE_PIC_OPERAND_P (operands[1])) + abort(); return "mov{l}\t{%1, %0|%0, %1}"; } } [(set (attr "type") - (cond [(eq_attr "alternative" "2") - (const_string "mmxadd") - (eq_attr "alternative" "3,4,5") + (cond [(eq_attr "alternative" "2,3,4") (const_string "mmxmov") - (eq_attr "alternative" "6") - (const_string "sselog1") - (eq_attr "alternative" "7,8,9,10,11") + (eq_attr "alternative" "5,6,7") (const_string "ssemov") - (match_operand:DI 1 "pic_32bit_operand" "") + (and (ne (symbol_ref "flag_pic") (const_int 0)) + (match_operand:SI 1 "symbolic_operand" "")) (const_string "lea") ] (const_string "imov"))) - (set (attr "mode") - (cond [(eq_attr "alternative" "2,3") - (const_string "DI") - (eq_attr "alternative" "6,7") - (if_then_else - (eq (symbol_ref "TARGET_SSE2") (const_int 0)) - (const_string "V4SF") - (const_string "TI")) - (and (eq_attr "alternative" "8,9,10,11") - (eq (symbol_ref "TARGET_SSE2") (const_int 0))) - (const_string "SF") - ] - (const_string "SI")))]) + (set_attr "mode" "SI,SI,DI,SI,SI,TI,SI,SI")]) ;; Stores and loads of ax to arbitrary constant address. ;; We fake an second form of instruction to force reload to load address @@ -1268,7 +1263,8 @@ [(set_attr "type" "imov") (set_attr "mode" "SI") (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector")]) + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) (define_expand "movhi" [(set (match_operand:HI 0 "nonimmediate_operand" "") @@ -1277,12 +1273,14 @@ "ix86_expand_move (HImode, operands); DONE;") (define_insn "*pushhi2" - [(set (match_operand:HI 0 "push_operand" "=X") - (match_operand:HI 1 "nonmemory_no_elim_operand" "rn"))] + [(set (match_operand:HI 0 "push_operand" "=<,<") + (match_operand:HI 1 "general_no_elim_operand" "n,r*m"))] "!TARGET_64BIT" - "push{l}\t%k1" + "@ + push{w}\t{|WORD PTR }%1 + push{w}\t%1" [(set_attr "type" "push") - (set_attr "mode" "SI")]) + (set_attr "mode" "HI")]) ;; For 64BIT abi we always round up to 8 bytes. (define_insn "*pushhi2_rex64" @@ -1291,7 +1289,7 @@ "TARGET_64BIT" "push{q}\t%q1" [(set_attr "type" "push") - (set_attr "mode" "DI")]) + (set_attr "mode" "QI")]) (define_insn "*movhi_1" [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m") @@ -1312,9 +1310,7 @@ } } [(set (attr "type") - (cond [(ne (symbol_ref "optimize_size") (const_int 0)) - (const_string "imov") - (and (eq_attr "alternative" "0") + (cond [(and (eq_attr "alternative" "0") (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") (const_int 0)) (eq (symbol_ref "TARGET_HIMODE_MATH") @@ -1385,7 +1381,8 @@ [(set_attr "type" "imov") (set_attr "mode" "SI") (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector")]) + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) (define_insn "*swaphi_2" [(set (match_operand:HI 0 "register_operand" "+r") @@ -1397,7 +1394,8 @@ [(set_attr "type" "imov") (set_attr "mode" "HI") (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector")]) + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) (define_expand "movstricthi" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "")) @@ -1421,7 +1419,7 @@ (define_insn "*movstricthi_xor" [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r")) (match_operand:HI 1 "const0_operand" "i")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && ((!TARGET_USE_MOV0 && !TARGET_PARTIAL_REG_STALL) || optimize_size)" "xor{w}\t{%0, %0|%0, %0}" @@ -1436,16 +1434,18 @@ "ix86_expand_move (QImode, operands); DONE;") ;; emit_push_insn when it calls move_by_pieces requires an insn to -;; "push a byte". But actually we use pushl, which has the effect -;; of rounding the amount pushed up to a word. +;; "push a byte". But actually we use pushw, which has the effect +;; of rounding the amount pushed up to a halfword. (define_insn "*pushqi2" - [(set (match_operand:QI 0 "push_operand" "=X") - (match_operand:QI 1 "nonmemory_no_elim_operand" "rn"))] + [(set (match_operand:QI 0 "push_operand" "=X,X") + (match_operand:QI 1 "nonmemory_no_elim_operand" "n,r"))] "!TARGET_64BIT" - "push{l}\t%k1" + "@ + push{w}\t{|word ptr }%1 + push{w}\t%w1" [(set_attr "type" "push") - (set_attr "mode" "SI")]) + (set_attr "mode" "HI")]) ;; For 64BIT abi we always round up to 8 bytes. (define_insn "*pushqi2_rex64" @@ -1454,7 +1454,7 @@ "TARGET_64BIT" "push{q}\t%q1" [(set_attr "type" "push") - (set_attr "mode" "DI")]) + (set_attr "mode" "QI")]) ;; Situation is quite tricky about when to choose full sized (SImode) move ;; over QImode moves. For Q_REG -> Q_REG move we use full size only for @@ -1474,7 +1474,8 @@ switch (get_attr_type (insn)) { case TYPE_IMOVX: - gcc_assert (ANY_QI_REG_P (operands[1]) || GET_CODE (operands[1]) == MEM); + if (!ANY_QI_REG_P (operands[1]) && GET_CODE (operands[1]) != MEM) + abort (); return "movz{bl|x}\t{%1, %k0|%k0, %1}"; default: if (get_attr_mode (insn) == MODE_SI) @@ -1484,12 +1485,7 @@ } } [(set (attr "type") - (cond [(and (eq_attr "alternative" "5") - (not (match_operand:QI 1 "aligned_operand" ""))) - (const_string "imovx") - (ne (symbol_ref "optimize_size") (const_int 0)) - (const_string "imov") - (and (eq_attr "alternative" "3") + (cond [(and (eq_attr "alternative" "3") (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") (const_int 0)) (eq (symbol_ref "TARGET_QIMODE_MATH") @@ -1511,17 +1507,13 @@ (eq_attr "type" "imovx") (const_string "SI") (and (eq_attr "type" "imov") - (and (eq_attr "alternative" "0,1") - (and (ne (symbol_ref "TARGET_PARTIAL_REG_DEPENDENCY") - (const_int 0)) - (and (eq (symbol_ref "optimize_size") - (const_int 0)) - (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") - (const_int 0)))))) + (and (eq_attr "alternative" "0,1,2") + (ne (symbol_ref "TARGET_PARTIAL_REG_DEPENDENCY") + (const_int 0)))) (const_string "SI") ;; Avoid partial register stalls when not using QImode arithmetic (and (eq_attr "type" "imov") - (and (eq_attr "alternative" "0,1") + (and (eq_attr "alternative" "0,1,2") (and (ne (symbol_ref "TARGET_PARTIAL_REG_STALL") (const_int 0)) (eq (symbol_ref "TARGET_QIMODE_MATH") @@ -1539,7 +1531,8 @@ rtx op0, op1, op2; op0 = operands[0]; op1 = operands[1]; op2 = operands[2]; - gcc_assert (!reg_overlap_mentioned_p (op2, op0)); + if (reg_overlap_mentioned_p (op2, op0)) + abort (); if (! q_regs_operand (op1, QImode)) { emit_insn (gen_movqi (op2, op1)); @@ -1559,7 +1552,8 @@ [(set_attr "type" "imov") (set_attr "mode" "SI") (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector")]) + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) (define_insn "*swapqi_2" [(set (match_operand:QI 0 "register_operand" "+q") @@ -1571,7 +1565,8 @@ [(set_attr "type" "imov") (set_attr "mode" "QI") (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector")]) + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) (define_expand "movstrictqi" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "")) @@ -1595,7 +1590,7 @@ (define_insn "*movstrictqi_xor" [(set (strict_low_part (match_operand:QI 0 "q_regs_operand" "+q")) (match_operand:QI 1 "const0_operand" "i")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && (!TARGET_USE_MOV0 || optimize_size)" "xor{b}\t{%0, %0|%0, %0}" [(set_attr "type" "alu1") @@ -1707,16 +1702,6 @@ (set_attr "memory" "load") (set_attr "mode" "QI")]) -(define_insn "*movdi_extzv_1" - [(set (match_operand:DI 0 "register_operand" "=R") - (zero_extract:DI (match_operand 1 "ext_register_operand" "Q") - (const_int 8) - (const_int 8)))] - "TARGET_64BIT" - "movz{bl|x}\t{%h1, %k0|%k0, %h1}" - [(set_attr "type" "imovx") - (set_attr "mode" "DI")]) - (define_insn "*movsi_extzv_1" [(set (match_operand:SI 0 "register_operand" "=R") (zero_extract:SI (match_operand 1 "ext_register_operand" "Q") @@ -1823,7 +1808,7 @@ "!TARGET_64BIT" "#") -(define_insn "*pushdi2_rex64" +(define_insn "pushdi2_rex64" [(set (match_operand:DI 0 "push_operand" "=<,!<") (match_operand:DI 1 "general_no_elim_operand" "re*m,n"))] "TARGET_64BIT" @@ -1849,7 +1834,6 @@ ;; We need to define this as both peepholer and splitter for case ;; peephole2 pass is not run. -;; "&& 1" is needed to keep it from matching the previous pattern. (define_peephole2 [(set (match_operand:DI 0 "push_operand" "") (match_operand:DI 1 "immediate_operand" ""))] @@ -1867,7 +1851,7 @@ [(set (match_operand:DI 0 "push_operand" "") (match_operand:DI 1 "immediate_operand" ""))] "TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? flow2_completed : reload_completed) + ? flow2_completed : reload_completed) && !symbolic_operand (operands[1], DImode) && !x86_64_immediate_operand (operands[1], DImode)" [(set (match_dup 0) (match_dup 1)) @@ -1889,9 +1873,9 @@ (define_insn "*popdi1_epilogue_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=r*m") - (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) - (plus:DI (reg:DI SP_REG) (const_int 8))) + (mem:DI (reg:DI 7))) + (set (reg:DI 7) + (plus:DI (reg:DI 7) (const_int 8))) (clobber (mem:BLK (scratch)))] "TARGET_64BIT" "pop{q}\t%0" @@ -1900,9 +1884,9 @@ (define_insn "popdi1" [(set (match_operand:DI 0 "nonimmediate_operand" "=r*m") - (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) - (plus:DI (reg:DI SP_REG) (const_int 8)))] + (mem:DI (reg:DI 7))) + (set (reg:DI 7) + (plus:DI (reg:DI 7) (const_int 8)))] "TARGET_64BIT" "pop{q}\t%0" [(set_attr "type" "pop") @@ -1911,7 +1895,7 @@ (define_insn "*movdi_xor_rex64" [(set (match_operand:DI 0 "register_operand" "=r") (match_operand:DI 1 "const0_operand" "i")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (!TARGET_USE_MOV0 || optimize_size) && reload_completed" "xor{l}\t{%k0, %k0|%k0, %k0}" @@ -1922,7 +1906,7 @@ (define_insn "*movdi_or_rex64" [(set (match_operand:DI 0 "register_operand" "=r") (match_operand:DI 1 "const_int_operand" "i")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (TARGET_PENTIUM || optimize_size) && reload_completed && operands[1] == constm1_rtx" @@ -1935,27 +1919,20 @@ (set_attr "length_immediate" "1")]) (define_insn "*movdi_2" - [(set (match_operand:DI 0 "nonimmediate_operand" - "=r ,o ,*y,m*y,*y,*Y,m ,*Y,*Y,*x,m ,*x,*x") - (match_operand:DI 1 "general_operand" - "riFo,riF,C ,*y ,m ,C ,*Y,*Y,m ,C ,*x,*x,m "))] - "!TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o,!m*y,!*y,!m,!*Y,!*Y") + (match_operand:DI 1 "general_operand" "riFo,riF,*y,m,*Y,*Y,m"))] + "!TARGET_64BIT + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "@ # # - pxor\t%0, %0 movq\t{%1, %0|%0, %1} movq\t{%1, %0|%0, %1} - pxor\t%0, %0 movq\t{%1, %0|%0, %1} movdqa\t{%1, %0|%0, %1} - movq\t{%1, %0|%0, %1} - xorps\t%0, %0 - movlps\t{%1, %0|%0, %1} - movaps\t{%1, %0|%0, %1} - movlps\t{%1, %0|%0, %1}" - [(set_attr "type" "*,*,mmx,mmxmov,mmxmov,sselog1,ssemov,ssemov,ssemov,sselog1,ssemov,ssemov,ssemov") - (set_attr "mode" "DI,DI,DI,DI,DI,TI,DI,TI,DI,V4SF,V2SF,V4SF,V2SF")]) + movq\t{%1, %0|%0, %1}" + [(set_attr "type" "*,*,mmx,mmx,ssemov,ssemov,ssemov") + (set_attr "mode" "DI,DI,DI,DI,DI,TI,DI")]) (define_split [(set (match_operand:DI 0 "push_operand" "") @@ -1976,19 +1953,14 @@ "ix86_split_long_move (operands); DONE;") (define_insn "*movdi_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" - "=r,r ,r,m ,!m,*y,*y,?rm,?*y,*x,*x,?rm,?*x,?*x,?*y") - (match_operand:DI 1 "general_operand" - "Z ,rem,i,re,n ,C ,*y,*y ,rm ,C ,*x,*x ,rm ,*y ,*x"))] - "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,mr,!mr,!*y,!rm,!*y,!*Y,!rm,!*Y") + (match_operand:DI 1 "general_operand" "Z,rem,i,re,n,*y,*y,rm,*Y,*Y,rm"))] + "TARGET_64BIT + && (TARGET_INTER_UNIT_MOVES || optimize_size) + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" { switch (get_attr_type (insn)) { - case TYPE_SSECVT: - if (which_alternative == 13) - return "movq2dq\t{%1, %0|%0, %1}"; - else - return "movdq2q\t{%1, %0|%0, %1}"; case TYPE_SSEMOV: if (get_attr_mode (insn) == MODE_TI) return "movdqa\t{%1, %0|%0, %1}"; @@ -1999,15 +1971,59 @@ if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1])) return "movd\t{%1, %0|%0, %1}"; return "movq\t{%1, %0|%0, %1}"; - case TYPE_SSELOG1: - case TYPE_MMXADD: - return "pxor\t%0, %0"; case TYPE_MULTI: return "#"; case TYPE_LEA: return "lea{q}\t{%a1, %0|%0, %a1}"; default: - gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1])); + if (flag_pic && !LEGITIMATE_PIC_OPERAND_P (operands[1])) + abort (); + if (get_attr_mode (insn) == MODE_SI) + return "mov{l}\t{%k1, %k0|%k0, %k1}"; + else if (which_alternative == 2) + return "movabs{q}\t{%1, %0|%0, %1}"; + else + return "mov{q}\t{%1, %0|%0, %1}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "5,6,7") + (const_string "mmxmov") + (eq_attr "alternative" "8,9,10") + (const_string "ssemov") + (eq_attr "alternative" "4") + (const_string "multi") + (and (ne (symbol_ref "flag_pic") (const_int 0)) + (match_operand:DI 1 "symbolic_operand" "")) + (const_string "lea") + ] + (const_string "imov"))) + (set_attr "modrm" "*,0,0,*,*,*,*,*,*,*,*") + (set_attr "length_immediate" "*,4,8,*,*,*,*,*,*,*,*") + (set_attr "mode" "SI,DI,DI,DI,SI,DI,DI,DI,TI,DI,DI")]) + +(define_insn "*movdi_1_rex64_nointerunit" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,mr,!mr,!*y,!m,!*y,!*Y,!m,!*Y") + (match_operand:DI 1 "general_operand" "Z,rem,i,re,n,*y,*y,m,*Y,*Y,m"))] + "TARGET_64BIT + && (!TARGET_INTER_UNIT_MOVES && !optimize_size) + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (get_attr_type (insn)) + { + case TYPE_SSEMOV: + if (get_attr_mode (insn) == MODE_TI) + return "movdqa\t{%1, %0|%0, %1}"; + /* FALLTHRU */ + case TYPE_MMXMOV: + return "movq\t{%1, %0|%0, %1}"; + case TYPE_MULTI: + return "#"; + case TYPE_LEA: + return "lea{q}\t{%a1, %0|%0, %a1}"; + default: + if (flag_pic && !LEGITIMATE_PIC_OPERAND_P (operands[1])) + abort (); if (get_attr_mode (insn) == MODE_SI) return "mov{l}\t{%k1, %k0|%k0, %k1}"; else if (which_alternative == 2) @@ -2017,25 +2033,20 @@ } } [(set (attr "type") - (cond [(eq_attr "alternative" "5") - (const_string "mmxadd") - (eq_attr "alternative" "6,7,8") + (cond [(eq_attr "alternative" "5,6,7") (const_string "mmxmov") - (eq_attr "alternative" "9") - (const_string "sselog1") - (eq_attr "alternative" "10,11,12") + (eq_attr "alternative" "8,9,10") (const_string "ssemov") - (eq_attr "alternative" "13,14") - (const_string "ssecvt") (eq_attr "alternative" "4") (const_string "multi") - (match_operand:DI 1 "pic_32bit_operand" "") + (and (ne (symbol_ref "flag_pic") (const_int 0)) + (match_operand:DI 1 "symbolic_operand" "")) (const_string "lea") ] (const_string "imov"))) - (set_attr "modrm" "*,0,0,*,*,*,*,*,*,*,*,*,*,*,*") - (set_attr "length_immediate" "*,4,8,*,*,*,*,*,*,*,*,*,*,*,*") - (set_attr "mode" "SI,DI,DI,DI,SI,DI,DI,DI,DI,TI,TI,DI,DI,DI,DI")]) + (set_attr "modrm" "*,0,0,*,*,*,*,*,*,*,*") + (set_attr "length_immediate" "*,4,8,*,*,*,*,*,*,*,*") + (set_attr "mode" "SI,DI,DI,DI,SI,DI,DI,DI,TI,DI,DI")]) ;; Stores and loads of ax to arbitrary constant address. ;; We fake an second form of instruction to force reload to load address @@ -2083,7 +2094,6 @@ ;; We need to define this as both peepholer and splitter for case ;; peephole2 pass is not run. -;; "&& 1" is needed to keep it from matching the previous pattern. (define_peephole2 [(set (match_operand:DI 0 "memory_operand" "") (match_operand:DI 1 "immediate_operand" ""))] @@ -2097,7 +2107,7 @@ [(set (match_operand:DI 0 "memory_operand" "") (match_operand:DI 1 "immediate_operand" ""))] "TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? flow2_completed : reload_completed) + ? flow2_completed : reload_completed) && !symbolic_operand (operands[1], DImode) && !x86_64_immediate_operand (operands[1], DImode)" [(set (match_dup 2) (match_dup 3)) @@ -2114,105 +2124,8 @@ [(set_attr "type" "imov") (set_attr "mode" "DI") (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector")]) - -(define_expand "movti" - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (match_operand:TI 1 "nonimmediate_operand" ""))] - "TARGET_SSE || TARGET_64BIT" -{ - if (TARGET_64BIT) - ix86_expand_move (TImode, operands); - else - ix86_expand_vector_move (TImode, operands); - DONE; -}) - -(define_insn "*movti_internal" - [(set (match_operand:TI 0 "nonimmediate_operand" "=x,x,m") - (match_operand:TI 1 "vector_move_operand" "C,xm,x"))] - "TARGET_SSE && !TARGET_64BIT - && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" -{ - switch (which_alternative) - { - case 0: - if (get_attr_mode (insn) == MODE_V4SF) - return "xorps\t%0, %0"; - else - return "pxor\t%0, %0"; - case 1: - case 2: - if (get_attr_mode (insn) == MODE_V4SF) - return "movaps\t{%1, %0|%0, %1}"; - else - return "movdqa\t{%1, %0|%0, %1}"; - default: - gcc_unreachable (); - } -} - [(set_attr "type" "sselog1,ssemov,ssemov") - (set (attr "mode") - (cond [(ior (eq (symbol_ref "TARGET_SSE2") (const_int 0)) - (ne (symbol_ref "optimize_size") (const_int 0))) - (const_string "V4SF") - (and (eq_attr "alternative" "2") - (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") - (const_int 0))) - (const_string "V4SF")] - (const_string "TI")))]) - -(define_insn "*movti_rex64" - [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o,x,x,xm") - (match_operand:TI 1 "general_operand" "riFo,riF,C,xm,x"))] - "TARGET_64BIT - && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" -{ - switch (which_alternative) - { - case 0: - case 1: - return "#"; - case 2: - if (get_attr_mode (insn) == MODE_V4SF) - return "xorps\t%0, %0"; - else - return "pxor\t%0, %0"; - case 3: - case 4: - if (get_attr_mode (insn) == MODE_V4SF) - return "movaps\t{%1, %0|%0, %1}"; - else - return "movdqa\t{%1, %0|%0, %1}"; - default: - gcc_unreachable (); - } -} - [(set_attr "type" "*,*,sselog1,ssemov,ssemov") - (set (attr "mode") - (cond [(eq_attr "alternative" "2,3") - (if_then_else - (ne (symbol_ref "optimize_size") - (const_int 0)) - (const_string "V4SF") - (const_string "TI")) - (eq_attr "alternative" "4") - (if_then_else - (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") - (const_int 0)) - (ne (symbol_ref "optimize_size") - (const_int 0))) - (const_string "V4SF") - (const_string "TI"))] - (const_string "DI")))]) - -(define_split - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (match_operand:TI 1 "general_operand" ""))] - "reload_completed && !SSE_REG_P (operands[0]) - && !SSE_REG_P (operands[1])" - [(const_int 0)] - "ix86_split_long_move (operands); DONE;") + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) (define_expand "movsf" [(set (match_operand:SF 0 "nonimmediate_operand" "") @@ -2222,28 +2135,38 @@ (define_insn "*pushsf" [(set (match_operand:SF 0 "push_operand" "=<,<,<") - (match_operand:SF 1 "general_no_elim_operand" "f,rFm,x"))] + (match_operand:SF 1 "general_no_elim_operand" "f#rx,rFm#fx,x#rf"))] "!TARGET_64BIT" { - /* Anything else should be already split before reg-stack. */ - gcc_assert (which_alternative == 1); - return "push{l}\t%1"; + switch (which_alternative) + { + case 1: + return "push{l}\t%1"; + + default: + /* This insn should be already split before reg-stack. */ + abort (); + } } [(set_attr "type" "multi,push,multi") - (set_attr "unit" "i387,*,*") (set_attr "mode" "SF,SI,SF")]) (define_insn "*pushsf_rex64" [(set (match_operand:SF 0 "push_operand" "=X,X,X") - (match_operand:SF 1 "nonmemory_no_elim_operand" "f,rF,x"))] + (match_operand:SF 1 "nonmemory_no_elim_operand" "f#rx,rF#fx,x#rf"))] "TARGET_64BIT" { - /* Anything else should be already split before reg-stack. */ - gcc_assert (which_alternative == 1); - return "push{q}\t%q1"; + switch (which_alternative) + { + case 1: + return "push{q}\t%q1"; + + default: + /* This insn should be already split before reg-stack. */ + abort (); + } } [(set_attr "type" "multi,push,multi") - (set_attr "unit" "i387,*,*") (set_attr "mode" "SF,DI,SF")]) (define_split @@ -2262,22 +2185,21 @@ [(set (match_operand:SF 0 "push_operand" "") (match_operand:SF 1 "any_fp_register_operand" ""))] "!TARGET_64BIT" - [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) - (set (mem:SF (reg:SI SP_REG)) (match_dup 1))]) + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -4))) + (set (mem:SF (reg:SI 7)) (match_dup 1))]) (define_split [(set (match_operand:SF 0 "push_operand" "") (match_operand:SF 1 "any_fp_register_operand" ""))] "TARGET_64BIT" - [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -8))) - (set (mem:SF (reg:DI SP_REG)) (match_dup 1))]) + [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -8))) + (set (mem:SF (reg:DI 7)) (match_dup 1))]) (define_insn "*movsf_1" - [(set (match_operand:SF 0 "nonimmediate_operand" - "=f,m ,f,r ,m ,x,x,x ,m ,!*y,!rm,!*y") - (match_operand:SF 1 "general_operand" - "fm,f,G ,rmF,Fr,C ,x ,xm,x,rm ,*y ,*y"))] - "!(MEM_P (operands[0]) && MEM_P (operands[1])) + [(set (match_operand:SF 0 "nonimmediate_operand" "=f#xr,m,f#xr,r#xf,m,x#rf,x#rf,x#rf,m,!*y,!rm,!*y") + (match_operand:SF 1 "general_operand" "fm#rx,f#rx,G,rmF#fx,Fr#fx,C,x,xm#rf,x#rf,rm,*y,*y"))] + "(TARGET_INTER_UNIT_MOVES || optimize_size) + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) && (reload_in_progress || reload_completed || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) || GET_CODE (operands[1]) != CONST_DOUBLE @@ -2286,7 +2208,13 @@ switch (which_alternative) { case 0: - return output_387_reg_move (insn, operands); + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; case 1: if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) @@ -2322,10 +2250,10 @@ return "movq\t{%1, %0|%0, %1}"; default: - gcc_unreachable (); + abort(); } } - [(set_attr "type" "fmov,fmov,fmov,imov,imov,sselog1,ssemov,ssemov,ssemov,mmxmov,mmxmov,mmxmov") + [(set_attr "type" "fmov,fmov,fmov,imov,imov,ssemov,ssemov,ssemov,ssemov,mmxmov,mmxmov,mmxmov") (set (attr "mode") (cond [(eq_attr "alternative" "3,4,9,10") (const_string "SI") @@ -2353,7 +2281,106 @@ (if_then_else (ior (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") (const_int 0)) - (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") + (ne (symbol_ref "TARGET_SSE_PARTIAL_REGS") + (const_int 0))) + (const_string "V4SF") + (const_string "SF")) + (eq_attr "alternative" "11") + (const_string "DI")] + (const_string "SF")))]) + +(define_insn "*movsf_1_nointerunit" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f#xr,m,f#xr,r#xf,m,x#rf,x#rf,x#rf,m,!*y,!m,!*y") + (match_operand:SF 1 "general_operand" "fm#rx,f#rx,G,rmF#fx,Fr#fx,C,x,xm#rf,x#rf,m,*y,*y"))] + "(!TARGET_INTER_UNIT_MOVES && !optimize_size) + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && (reload_in_progress || reload_completed + || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) + || GET_CODE (operands[1]) != CONST_DOUBLE + || memory_operand (operands[0], SFmode))" +{ + switch (which_alternative) + { + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + { + if (REGNO (operands[0]) == FIRST_STACK_REG + && TARGET_USE_FFREEP) + return "ffreep\t%y0"; + return "fstp\t%y0"; + } + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; + + case 1: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + + case 2: + return standard_80387_constant_opcode (operands[1]); + + case 3: + case 4: + return "mov{l}\t{%1, %0|%0, %1}"; + case 5: + if (get_attr_mode (insn) == MODE_TI) + return "pxor\t%0, %0"; + else + return "xorps\t%0, %0"; + case 6: + if (get_attr_mode (insn) == MODE_V4SF) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movss\t{%1, %0|%0, %1}"; + case 7: + case 8: + return "movss\t{%1, %0|%0, %1}"; + + case 9: + case 10: + return "movd\t{%1, %0|%0, %1}"; + + case 11: + return "movq\t{%1, %0|%0, %1}"; + + default: + abort(); + } +} + [(set_attr "type" "fmov,fmov,fmov,imov,imov,ssemov,ssemov,ssemov,ssemov,mmxmov,mmxmov,mmxmov") + (set (attr "mode") + (cond [(eq_attr "alternative" "3,4,9,10") + (const_string "SI") + (eq_attr "alternative" "5") + (if_then_else + (and (and (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") + (const_int 0)) + (ne (symbol_ref "TARGET_SSE2") + (const_int 0))) + (eq (symbol_ref "optimize_size") + (const_int 0))) + (const_string "TI") + (const_string "V4SF")) + /* For architectures resolving dependencies on + whole SSE registers use APS move to break dependency + chains, otherwise use short move to avoid extra work. + + Do the same for architectures resolving dependencies on + the parts. While in DF mode it is better to always handle + just register parts, the SF mode is different due to lack + of instructions to load just part of the register. It is + better to maintain the whole registers in single format + to avoid problems on using packed logical operations. */ + (eq_attr "alternative" "6") + (if_then_else + (ior (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") + (const_int 0)) + (ne (symbol_ref "TARGET_SSE_PARTIAL_REGS") (const_int 0))) (const_string "V4SF") (const_string "SF")) @@ -2362,11 +2389,11 @@ (const_string "SF")))]) (define_insn "*swapsf" - [(set (match_operand:SF 0 "fp_register_operand" "+f") - (match_operand:SF 1 "fp_register_operand" "+f")) + [(set (match_operand:SF 0 "register_operand" "+f") + (match_operand:SF 1 "register_operand" "+f")) (set (match_dup 1) (match_dup 0))] - "reload_completed || TARGET_80387" + "reload_completed || !TARGET_SSE" { if (STACK_TOP_P (operands[0])) return "fxch\t%1"; @@ -2389,26 +2416,24 @@ (define_insn "*pushdf_nointeger" [(set (match_operand:DF 0 "push_operand" "=<,<,<,<") - (match_operand:DF 1 "general_no_elim_operand" "f,Fo,*r,Y"))] + (match_operand:DF 1 "general_no_elim_operand" "f#Y,Fo#fY,*r#fY,Y#f"))] "!TARGET_64BIT && !TARGET_INTEGER_DFMODE_MOVES" { /* This insn should be already split before reg-stack. */ - gcc_unreachable (); + abort (); } [(set_attr "type" "multi") - (set_attr "unit" "i387,*,*,*") (set_attr "mode" "DF,SI,SI,DF")]) (define_insn "*pushdf_integer" [(set (match_operand:DF 0 "push_operand" "=<,<,<") - (match_operand:DF 1 "general_no_elim_operand" "f,rFo,Y"))] + (match_operand:DF 1 "general_no_elim_operand" "f#rY,rFo#fY,Y#rf"))] "TARGET_64BIT || TARGET_INTEGER_DFMODE_MOVES" { /* This insn should be already split before reg-stack. */ - gcc_unreachable (); + abort (); } [(set_attr "type" "multi") - (set_attr "unit" "i387,*,*") (set_attr "mode" "DF,SI,DF")]) ;; %%% Kill this when call knows how to work this out. @@ -2416,16 +2441,16 @@ [(set (match_operand:DF 0 "push_operand" "") (match_operand:DF 1 "any_fp_register_operand" ""))] "!TARGET_64BIT && reload_completed" - [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -8))) - (set (mem:DF (reg:SI SP_REG)) (match_dup 1))] + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (set (mem:DF (reg:SI 7)) (match_dup 1))] "") (define_split [(set (match_operand:DF 0 "push_operand" "") (match_operand:DF 1 "any_fp_register_operand" ""))] "TARGET_64BIT && reload_completed" - [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -8))) - (set (mem:DF (reg:DI SP_REG)) (match_dup 1))] + [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -8))) + (set (mem:DF (reg:DI 7)) (match_dup 1))] "") (define_split @@ -2440,10 +2465,8 @@ ;; when optimizing for size. (define_insn "*movdf_nointeger" - [(set (match_operand:DF 0 "nonimmediate_operand" - "=f,m,f,*r ,o ,Y*x,Y*x,Y*x ,m ") - (match_operand:DF 1 "general_operand" - "fm,f,G,*roF,F*r,C ,Y*x,mY*x,Y*x"))] + [(set (match_operand:DF 0 "nonimmediate_operand" "=f#Y,m,f#Y,*r,o,Y#f,Y#f,Y#f,m") + (match_operand:DF 1 "general_operand" "fm#Y,f#Y,G,*roF,F*r,C,Y#f,YHm#f,Y#f"))] "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) && ((optimize_size || !TARGET_INTEGER_DFMODE_MOVES) && !TARGET_64BIT) && (reload_in_progress || reload_completed @@ -2454,7 +2477,18 @@ switch (which_alternative) { case 0: - return output_387_reg_move (insn, operands); + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + { + if (REGNO (operands[0]) == FIRST_STACK_REG + && TARGET_USE_FFREEP) + return "ffreep\t%y0"; + return "fstp\t%y0"; + } + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; case 1: if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) @@ -2478,49 +2512,36 @@ case MODE_TI: return "pxor\t%0, %0"; default: - gcc_unreachable (); + abort (); } case 6: - case 7: - case 8: switch (get_attr_mode (insn)) { case MODE_V4SF: return "movaps\t{%1, %0|%0, %1}"; case MODE_V2DF: return "movapd\t{%1, %0|%0, %1}"; - case MODE_TI: - return "movdqa\t{%1, %0|%0, %1}"; - case MODE_DI: - return "movq\t{%1, %0|%0, %1}"; case MODE_DF: return "movsd\t{%1, %0|%0, %1}"; - case MODE_V1DF: - return "movlpd\t{%1, %0|%0, %1}"; - case MODE_V2SF: - return "movlps\t{%1, %0|%0, %1}"; default: - gcc_unreachable (); + abort (); } + case 7: + if (get_attr_mode (insn) == MODE_V2DF) + return "movlpd\t{%1, %0|%0, %1}"; + else + return "movsd\t{%1, %0|%0, %1}"; + case 8: + return "movsd\t{%1, %0|%0, %1}"; default: - gcc_unreachable (); + abort(); } } - [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov") + [(set_attr "type" "fmov,fmov,fmov,multi,multi,ssemov,ssemov,ssemov,ssemov") (set (attr "mode") - (cond [(eq_attr "alternative" "0,1,2") - (const_string "DF") - (eq_attr "alternative" "3,4") + (cond [(eq_attr "alternative" "3,4") (const_string "SI") - - /* For SSE1, we have many fewer alternatives. */ - (eq (symbol_ref "TARGET_SSE2") (const_int 0)) - (cond [(eq_attr "alternative" "5,6") - (const_string "V4SF") - ] - (const_string "V2SF")) - /* xorps is one byte shorter. */ (eq_attr "alternative" "5") (cond [(ne (symbol_ref "optimize_size") @@ -2528,10 +2549,8 @@ (const_string "V4SF") (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") (const_int 0)) - (const_string "TI") - ] + (const_string "TI")] (const_string "V2DF")) - /* For architectures resolving dependencies on whole SSE registers use APD move to break dependency chains, otherwise use short move to avoid extra work. @@ -2539,31 +2558,27 @@ movaps encodes one byte shorter. */ (eq_attr "alternative" "6") (cond - [(ne (symbol_ref "optimize_size") - (const_int 0)) - (const_string "V4SF") - (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") - (const_int 0)) - (const_string "V2DF") - ] + [(ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") + (const_int 0)) + (const_string "V2DF")] (const_string "DF")) /* For architectures resolving dependencies on register parts we may avoid extra work to zero out upper part of register. */ (eq_attr "alternative" "7") (if_then_else - (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") + (ne (symbol_ref "TARGET_SSE_PARTIAL_REGS") (const_int 0)) - (const_string "V1DF") - (const_string "DF")) - ] - (const_string "DF")))]) + (const_string "V2DF") + (const_string "DF"))] + (const_string "DF")))]) (define_insn "*movdf_integer" - [(set (match_operand:DF 0 "nonimmediate_operand" - "=f,m,f,r ,o ,Y*x,Y*x,Y*x,m ") - (match_operand:DF 1 "general_operand" - "fm,f,G,roF,Fr,C ,Y*x,m ,Y*x"))] + [(set (match_operand:DF 0 "nonimmediate_operand" "=f#Yr,m,f#Yr,r#Yf,o,Y#rf,Y#rf,Y#rf,m") + (match_operand:DF 1 "general_operand" "fm#Yr,f#Yr,G,roF#Yf,Fr#Yf,C,Y#rf,Ym#rf,Y#rf"))] "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) && ((!optimize_size && TARGET_INTEGER_DFMODE_MOVES) || TARGET_64BIT) && (reload_in_progress || reload_completed @@ -2574,7 +2589,18 @@ switch (which_alternative) { case 0: - return output_387_reg_move (insn, operands); + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + { + if (REGNO (operands[0]) == FIRST_STACK_REG + && TARGET_USE_FFREEP) + return "ffreep\t%y0"; + return "fstp\t%y0"; + } + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; case 1: if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) @@ -2599,49 +2625,36 @@ case MODE_TI: return "pxor\t%0, %0"; default: - gcc_unreachable (); + abort (); } case 6: - case 7: - case 8: switch (get_attr_mode (insn)) { case MODE_V4SF: return "movaps\t{%1, %0|%0, %1}"; case MODE_V2DF: return "movapd\t{%1, %0|%0, %1}"; - case MODE_TI: - return "movdqa\t{%1, %0|%0, %1}"; - case MODE_DI: - return "movq\t{%1, %0|%0, %1}"; case MODE_DF: return "movsd\t{%1, %0|%0, %1}"; - case MODE_V1DF: - return "movlpd\t{%1, %0|%0, %1}"; - case MODE_V2SF: - return "movlps\t{%1, %0|%0, %1}"; default: - gcc_unreachable (); + abort (); } + case 7: + if (get_attr_mode (insn) == MODE_V2DF) + return "movlpd\t{%1, %0|%0, %1}"; + else + return "movsd\t{%1, %0|%0, %1}"; + case 8: + return "movsd\t{%1, %0|%0, %1}"; default: - gcc_unreachable(); + abort(); } } - [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov") + [(set_attr "type" "fmov,fmov,fmov,multi,multi,ssemov,ssemov,ssemov,ssemov") (set (attr "mode") - (cond [(eq_attr "alternative" "0,1,2") - (const_string "DF") - (eq_attr "alternative" "3,4") + (cond [(eq_attr "alternative" "3,4") (const_string "SI") - - /* For SSE1, we have many fewer alternatives. */ - (eq (symbol_ref "TARGET_SSE2") (const_int 0)) - (cond [(eq_attr "alternative" "5,6") - (const_string "V4SF") - ] - (const_string "V2SF")) - /* xorps is one byte shorter. */ (eq_attr "alternative" "5") (cond [(ne (symbol_ref "optimize_size") @@ -2649,36 +2662,32 @@ (const_string "V4SF") (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") (const_int 0)) - (const_string "TI") - ] + (const_string "TI")] (const_string "V2DF")) - /* For architectures resolving dependencies on whole SSE registers use APD move to break dependency - chains, otherwise use short move to avoid extra work. + chains, otherwise use short move to avoid extra work. movaps encodes one byte shorter. */ (eq_attr "alternative" "6") (cond - [(ne (symbol_ref "optimize_size") - (const_int 0)) - (const_string "V4SF") - (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") - (const_int 0)) - (const_string "V2DF") - ] + [(ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") + (const_int 0)) + (const_string "V2DF")] (const_string "DF")) /* For architectures resolving dependencies on register parts we may avoid extra work to zero out upper part of register. */ (eq_attr "alternative" "7") (if_then_else - (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") + (ne (symbol_ref "TARGET_SSE_PARTIAL_REGS") (const_int 0)) - (const_string "V1DF") - (const_string "DF")) - ] - (const_string "DF")))]) + (const_string "V2DF") + (const_string "DF"))] + (const_string "DF")))]) (define_split [(set (match_operand:DF 0 "nonimmediate_operand" "") @@ -2695,11 +2704,11 @@ "ix86_split_long_move (operands); DONE;") (define_insn "*swapdf" - [(set (match_operand:DF 0 "fp_register_operand" "+f") - (match_operand:DF 1 "fp_register_operand" "+f")) + [(set (match_operand:DF 0 "register_operand" "+f") + (match_operand:DF 1 "register_operand" "+f")) (set (match_dup 1) (match_dup 0))] - "reload_completed || TARGET_80387" + "reload_completed || !TARGET_SSE2" { if (STACK_TOP_P (operands[0])) return "fxch\t%1"; @@ -2728,22 +2737,20 @@ "optimize_size" { /* This insn should be already split before reg-stack. */ - gcc_unreachable (); + abort (); } [(set_attr "type" "multi") - (set_attr "unit" "i387,*,*") (set_attr "mode" "XF,SI,SI")]) (define_insn "*pushxf_integer" [(set (match_operand:XF 0 "push_operand" "=<,<") - (match_operand:XF 1 "general_no_elim_operand" "f,ro"))] + (match_operand:XF 1 "general_no_elim_operand" "f#r,ro#f"))] "!optimize_size" { /* This insn should be already split before reg-stack. */ - gcc_unreachable (); + abort (); } [(set_attr "type" "multi") - (set_attr "unit" "i387,*") (set_attr "mode" "XF,SI")]) (define_split @@ -2760,16 +2767,16 @@ [(set (match_operand:XF 0 "push_operand" "") (match_operand:XF 1 "any_fp_register_operand" ""))] "!TARGET_64BIT" - [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_dup 2))) - (set (mem:XF (reg:SI SP_REG)) (match_dup 1))] + [(set (reg:SI 7) (plus:SI (reg:SI 7) (match_dup 2))) + (set (mem:XF (reg:SI 7)) (match_dup 1))] "operands[2] = GEN_INT (TARGET_128BIT_LONG_DOUBLE ? -16 : -12);") (define_split [(set (match_operand:XF 0 "push_operand" "") (match_operand:XF 1 "any_fp_register_operand" ""))] "TARGET_64BIT" - [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (match_dup 2))) - (set (mem:XF (reg:DI SP_REG)) (match_dup 1))] + [(set (reg:DI 7) (plus:DI (reg:DI 7) (match_dup 2))) + (set (mem:XF (reg:DI 7)) (match_dup 1))] "operands[2] = GEN_INT (TARGET_128BIT_LONG_DOUBLE ? -16 : -12);") ;; Do not use integer registers when optimizing for size @@ -2785,7 +2792,18 @@ switch (which_alternative) { case 0: - return output_387_reg_move (insn, operands); + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + { + if (REGNO (operands[0]) == FIRST_STACK_REG + && TARGET_USE_FFREEP) + return "ffreep\t%y0"; + return "fstp\t%y0"; + } + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; case 1: /* There is no non-popping store to memory for XFmode. So if @@ -2800,16 +2818,15 @@ case 3: case 4: return "#"; - default: - gcc_unreachable (); } + abort(); } [(set_attr "type" "fmov,fmov,fmov,multi,multi") (set_attr "mode" "XF,XF,XF,SI,SI")]) (define_insn "*movxf_integer" - [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,r,o") - (match_operand:XF 1 "general_operand" "fm,f,G,roF,Fr"))] + [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,o") + (match_operand:XF 1 "general_operand" "fm#r,f#r,G,roF#f,Fr#f"))] "!optimize_size && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) && (reload_in_progress || reload_completed @@ -2819,7 +2836,18 @@ switch (which_alternative) { case 0: - return output_387_reg_move (insn, operands); + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + { + if (REGNO (operands[0]) == FIRST_STACK_REG + && TARGET_USE_FFREEP) + return "ffreep\t%y0"; + return "fstp\t%y0"; + } + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; case 1: /* There is no non-popping store to memory for XFmode. So if @@ -2834,10 +2862,8 @@ case 3: case 4: return "#"; - - default: - gcc_unreachable (); } + abort(); } [(set_attr "type" "fmov,fmov,fmov,multi,multi") (set_attr "mode" "XF,XF,XF,SI,SI")]) @@ -2894,7 +2920,7 @@ (match_operand:XF 1 "register_operand" "+f")) (set (match_dup 1) (match_dup 0))] - "TARGET_80387" + "" { if (STACK_TOP_P (operands[0])) return "fxch\t%1"; @@ -2903,67 +2929,6 @@ } [(set_attr "type" "fxch") (set_attr "mode" "XF")]) - -(define_expand "movtf" - [(set (match_operand:TF 0 "nonimmediate_operand" "") - (match_operand:TF 1 "nonimmediate_operand" ""))] - "TARGET_64BIT" -{ - ix86_expand_move (TFmode, operands); - DONE; -}) - -(define_insn "*movtf_internal" - [(set (match_operand:TF 0 "nonimmediate_operand" "=r,o,x,x,xm") - (match_operand:TF 1 "general_operand" "riFo,riF,C,xm,x"))] - "TARGET_64BIT - && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" -{ - switch (which_alternative) - { - case 0: - case 1: - return "#"; - case 2: - if (get_attr_mode (insn) == MODE_V4SF) - return "xorps\t%0, %0"; - else - return "pxor\t%0, %0"; - case 3: - case 4: - if (get_attr_mode (insn) == MODE_V4SF) - return "movaps\t{%1, %0|%0, %1}"; - else - return "movdqa\t{%1, %0|%0, %1}"; - default: - gcc_unreachable (); - } -} - [(set_attr "type" "*,*,sselog1,ssemov,ssemov") - (set (attr "mode") - (cond [(eq_attr "alternative" "2,3") - (if_then_else - (ne (symbol_ref "optimize_size") - (const_int 0)) - (const_string "V4SF") - (const_string "TI")) - (eq_attr "alternative" "4") - (if_then_else - (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") - (const_int 0)) - (ne (symbol_ref "optimize_size") - (const_int 0))) - (const_string "V4SF") - (const_string "TI"))] - (const_string "DI")))]) - -(define_split - [(set (match_operand:TF 0 "nonimmediate_operand" "") - (match_operand:TF 1 "general_operand" ""))] - "reload_completed && !SSE_REG_P (operands[0]) - && !SSE_REG_P (operands[1])" - [(const_int 0)] - "ix86_split_long_move (operands); DONE;") ;; Zero extension instructions @@ -2983,7 +2948,7 @@ (define_insn "zero_extendhisi2_and" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extend:SI (match_operand:HI 1 "register_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_ZERO_EXTEND_WITH_AND && !optimize_size" "#" [(set_attr "type" "alu1") @@ -2992,10 +2957,10 @@ (define_split [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:HI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && !optimize_size" [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 65535))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_insn "*zero_extendhisi2_movzwl" @@ -3010,14 +2975,14 @@ [(parallel [(set (match_operand:HI 0 "register_operand" "") (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") (define_insn "*zero_extendqihi2_and" [(set (match_operand:HI 0 "register_operand" "=r,?&q") (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_ZERO_EXTEND_WITH_AND && !optimize_size" "#" [(set_attr "type" "alu1") @@ -3026,26 +2991,25 @@ (define_insn "*zero_extendqihi2_movzbw_and" [(set (match_operand:HI 0 "register_operand" "=r,r") (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm,0"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_ZERO_EXTEND_WITH_AND || optimize_size" "#" [(set_attr "type" "imovx,alu1") (set_attr "mode" "HI")]) -; zero extend to SImode here to avoid partial register stalls -(define_insn "*zero_extendqihi2_movzbl" +(define_insn "*zero_extendqihi2_movzbw" [(set (match_operand:HI 0 "register_operand" "=r") (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))] "(!TARGET_ZERO_EXTEND_WITH_AND || optimize_size) && reload_completed" - "movz{bl|x}\t{%1, %k0|%k0, %k1}" + "movz{bw|x}\t{%1, %0|%0, %1}" [(set_attr "type" "imovx") - (set_attr "mode" "SI")]) + (set_attr "mode" "HI")]) ;; For the movzbw case strip only the clobber (define_split [(set (match_operand:HI 0 "register_operand" "") (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && (!TARGET_ZERO_EXTEND_WITH_AND || optimize_size) && (!REG_P (operands[1]) || ANY_QI_REG_P (operands[1]))" @@ -3057,7 +3021,7 @@ (define_split [(set (match_operand:HI 0 "register_operand" "") (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && ANY_QI_REG_P (operands[0]) && (TARGET_ZERO_EXTEND_WITH_AND && !optimize_size) @@ -3070,25 +3034,25 @@ (define_split [(set (match_operand:HI 0 "register_operand" "") (zero_extend:HI (match_operand:QI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && true_regnum (operands[0]) == true_regnum (operands[1])" [(parallel [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_expand "zero_extendqisi2" [(parallel [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") (define_insn "*zero_extendqisi2_and" [(set (match_operand:SI 0 "register_operand" "=r,?&q") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,qm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_ZERO_EXTEND_WITH_AND && !optimize_size" "#" [(set_attr "type" "alu1") @@ -3097,7 +3061,7 @@ (define_insn "*zero_extendqisi2_movzbw_and" [(set (match_operand:SI 0 "register_operand" "=r,r") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm,0"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_ZERO_EXTEND_WITH_AND || optimize_size" "#" [(set_attr "type" "imovx,alu1") @@ -3115,7 +3079,7 @@ (define_split [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && (!TARGET_ZERO_EXTEND_WITH_AND || optimize_size) && (!REG_P (operands[1]) || ANY_QI_REG_P (operands[1]))" @@ -3127,7 +3091,7 @@ (define_split [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && ANY_QI_REG_P (operands[0]) && (ANY_QI_REG_P (operands[1]) || GET_CODE (operands[1]) == MEM) @@ -3141,11 +3105,11 @@ (define_split [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:QI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && true_regnum (operands[0]) == true_regnum (operands[1])" [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 255))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") ;; %%% Kill me once multi-word ops are sane. @@ -3161,10 +3125,24 @@ ") (define_insn "zero_extendsidi2_32" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?*o,?*y,?*Y") + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?*o,!?y,!?Y") + (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "0,rm,r,m,m"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && !TARGET_INTER_UNIT_MOVES" + "@ + # + # + # + movd\t{%1, %0|%0, %1} + movd\t{%1, %0|%0, %1}" + [(set_attr "mode" "SI,SI,SI,DI,TI") + (set_attr "type" "multi,multi,multi,mmxmov,ssemov")]) + +(define_insn "*zero_extendsidi2_32_1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?*o,!?y,!?Y") (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "0,rm,r,rm,rm"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT" + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_INTER_UNIT_MOVES" "@ # # @@ -3175,9 +3153,21 @@ (set_attr "type" "multi,multi,multi,mmxmov,ssemov")]) (define_insn "zero_extendsidi2_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o,?*y,?*Y") + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o,!?y,!?Y") + (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "rm,0,m,m")))] + "TARGET_64BIT && !TARGET_INTER_UNIT_MOVES" + "@ + mov\t{%k1, %k0|%k0, %k1} + # + movd\t{%1, %0|%0, %1} + movd\t{%1, %0|%0, %1}" + [(set_attr "type" "imovx,imov,mmxmov,ssemov") + (set_attr "mode" "SI,DI,DI,TI")]) + +(define_insn "*zero_extendsidi2_rex64_1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o,!?y,!*?") (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "rm,0,rm,rm")))] - "TARGET_64BIT" + "TARGET_64BIT && TARGET_INTER_UNIT_MOVES" "@ mov\t{%k1, %k0|%k0, %k1} # @@ -3196,7 +3186,7 @@ (define_split [(set (match_operand:DI 0 "register_operand" "") (zero_extend:DI (match_operand:SI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && reload_completed && true_regnum (operands[0]) == true_regnum (operands[1])" [(set (match_dup 4) (const_int 0))] @@ -3205,7 +3195,7 @@ (define_split [(set (match_operand:DI 0 "nonimmediate_operand" "") (zero_extend:DI (match_operand:SI 1 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && reload_completed && !SSE_REG_P (operands[0]) && !MMX_REG_P (operands[0])" [(set (match_dup 3) (match_dup 1)) @@ -3213,27 +3203,31 @@ "split_di (&operands[0], 1, &operands[3], &operands[4]);") (define_insn "zero_extendhidi2" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] "TARGET_64BIT" - "movz{wl|x}\t{%1, %k0|%k0, %1}" + "@ + movz{wl|x}\t{%1, %k0|%k0, %1} + movz{wq|x}\t{%1, %0|%0, %1}" [(set_attr "type" "imovx") - (set_attr "mode" "DI")]) + (set_attr "mode" "SI,DI")]) (define_insn "zero_extendqidi2" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "Q,m")))] "TARGET_64BIT" - "movz{bl|x}\t{%1, %k0|%k0, %1}" + "@ + movz{bl|x}\t{%1, %k0|%k0, %1} + movz{bq|x}\t{%1, %0|%0, %1}" [(set_attr "type" "imovx") - (set_attr "mode" "DI")]) + (set_attr "mode" "SI,DI")]) ;; Sign extension instructions (define_expand "extendsidi2" [(parallel [(set (match_operand:DI 0 "register_operand" "") (sign_extend:DI (match_operand:SI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG)) + (clobber (reg:CC 17)) (clobber (match_scratch:SI 2 ""))])] "" { @@ -3247,7 +3241,7 @@ (define_insn "*extendsidi2_1" [(set (match_operand:DI 0 "nonimmediate_operand" "=*A,r,?r,?*o") (sign_extend:DI (match_operand:SI 1 "register_operand" "0,0,r,r"))) - (clobber (reg:CC FLAGS_REG)) + (clobber (reg:CC 17)) (clobber (match_scratch:SI 2 "=X,X,X,&r"))] "!TARGET_64BIT" "#") @@ -3284,14 +3278,14 @@ (define_split [(set (match_operand:DI 0 "memory_operand" "") (sign_extend:DI (match_operand:SI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG)) + (clobber (reg:CC 17)) (clobber (match_operand:SI 2 "register_operand" ""))] "(reload_completed && dead_or_set_p (insn, operands[1]) && !reg_mentioned_p (operands[1], operands[0]))" [(set (match_dup 3) (match_dup 1)) (parallel [(set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31))) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (set (match_dup 4) (match_dup 1))] "split_di (&operands[0], 1, &operands[3], &operands[4]);") @@ -3299,7 +3293,7 @@ (define_split [(set (match_operand:DI 0 "memory_operand" "") (sign_extend:DI (match_operand:SI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG)) + (clobber (reg:CC 17)) (clobber (match_operand:SI 2 "register_operand" ""))] "reload_completed" [(const_int 0)] @@ -3329,7 +3323,7 @@ (define_split [(set (match_operand:DI 0 "register_operand" "") (sign_extend:DI (match_operand:SI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG)) + (clobber (reg:CC 17)) (clobber (match_scratch:SI 2 ""))] "reload_completed" [(const_int 0)] @@ -3466,15 +3460,15 @@ [(set (match_operand:DF 0 "push_operand" "") (float_extend:DF (match_operand:SF 1 "fp_register_operand" "")))] "!TARGET_64BIT" - [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -8))) - (set (mem:DF (reg:SI SP_REG)) (float_extend:DF (match_dup 1)))]) + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (set (mem:DF (reg:SI 7)) (float_extend:DF (match_dup 1)))]) (define_split [(set (match_operand:DF 0 "push_operand" "") (float_extend:DF (match_operand:SF 1 "fp_register_operand" "")))] "TARGET_64BIT" - [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -8))) - (set (mem:DF (reg:DI SP_REG)) (float_extend:DF (match_dup 1)))]) + [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -8))) + (set (mem:DF (reg:DI 7)) (float_extend:DF (match_dup 1)))]) (define_insn "*dummy_extendsfxf2" [(set (match_operand:XF 0 "push_operand" "=<") @@ -3486,117 +3480,89 @@ [(set (match_operand:XF 0 "push_operand" "") (float_extend:XF (match_operand:SF 1 "fp_register_operand" "")))] "" - [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_dup 2))) - (set (mem:XF (reg:SI SP_REG)) (float_extend:XF (match_dup 1)))] + [(set (reg:SI 7) (plus:SI (reg:SI 7) (match_dup 2))) + (set (mem:XF (reg:SI 7)) (float_extend:XF (match_dup 1)))] "operands[2] = GEN_INT (TARGET_128BIT_LONG_DOUBLE ? -16 : -12);") (define_split [(set (match_operand:XF 0 "push_operand" "") (float_extend:XF (match_operand:SF 1 "fp_register_operand" "")))] "TARGET_64BIT" - [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (match_dup 2))) - (set (mem:DF (reg:DI SP_REG)) (float_extend:XF (match_dup 1)))] + [(set (reg:DI 7) (plus:DI (reg:DI 7) (match_dup 2))) + (set (mem:DF (reg:DI 7)) (float_extend:XF (match_dup 1)))] "operands[2] = GEN_INT (TARGET_128BIT_LONG_DOUBLE ? -16 : -12);") (define_split [(set (match_operand:XF 0 "push_operand" "") (float_extend:XF (match_operand:DF 1 "fp_register_operand" "")))] "" - [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_dup 2))) - (set (mem:DF (reg:SI SP_REG)) (float_extend:XF (match_dup 1)))] + [(set (reg:SI 7) (plus:SI (reg:SI 7) (match_dup 2))) + (set (mem:DF (reg:SI 7)) (float_extend:XF (match_dup 1)))] "operands[2] = GEN_INT (TARGET_128BIT_LONG_DOUBLE ? -16 : -12);") (define_split [(set (match_operand:XF 0 "push_operand" "") (float_extend:XF (match_operand:DF 1 "fp_register_operand" "")))] "TARGET_64BIT" - [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (match_dup 2))) - (set (mem:XF (reg:DI SP_REG)) (float_extend:XF (match_dup 1)))] + [(set (reg:DI 7) (plus:DI (reg:DI 7) (match_dup 2))) + (set (mem:XF (reg:DI 7)) (float_extend:XF (match_dup 1)))] "operands[2] = GEN_INT (TARGET_128BIT_LONG_DOUBLE ? -16 : -12);") (define_expand "extendsfdf2" [(set (match_operand:DF 0 "nonimmediate_operand" "") (float_extend:DF (match_operand:SF 1 "general_operand" "")))] - "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" + "TARGET_80387 || TARGET_SSE2" { /* ??? Needed for compress_float_constant since all fp constants are LEGITIMATE_CONSTANT_P. */ if (GET_CODE (operands[1]) == CONST_DOUBLE) - { - if ((!TARGET_SSE2 || TARGET_MIX_SSE_I387) - && standard_80387_constant_p (operands[1]) > 0) - { - operands[1] = simplify_const_unary_operation - (FLOAT_EXTEND, DFmode, operands[1], SFmode); - emit_move_insn_1 (operands[0], operands[1]); - DONE; - } - operands[1] = validize_mem (force_const_mem (SFmode, operands[1])); - } + operands[1] = validize_mem (force_const_mem (SFmode, operands[1])); if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[1] = force_reg (SFmode, operands[1]); }) -(define_insn "*extendsfdf2_mixed" - [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,Y") - (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f,mY")))] - "TARGET_SSE2 && TARGET_MIX_SSE_I387 +(define_insn "*extendsfdf2_1" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f#Y,mf#Y,Y#f") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm#Y,f#Y,mY#f")))] + "(TARGET_80387 || TARGET_SSE2) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" { switch (which_alternative) { case 0: - return output_387_reg_move (insn, operands); + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; case 1: if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) return "fstp%z0\t%y0"; + else return "fst%z0\t%y0"; - case 2: return "cvtss2sd\t{%1, %0|%0, %1}"; default: - gcc_unreachable (); + abort (); } } [(set_attr "type" "fmov,fmov,ssecvt") (set_attr "mode" "SF,XF,DF")]) -(define_insn "*extendsfdf2_sse" - [(set (match_operand:DF 0 "nonimmediate_operand" "=Y") +(define_insn "*extendsfdf2_1_sse_only" + [(set (match_operand:DF 0 "register_operand" "=Y") (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "mY")))] - "TARGET_SSE2 && TARGET_SSE_MATH + "!TARGET_80387 && TARGET_SSE2 && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "cvtss2sd\t{%1, %0|%0, %1}" [(set_attr "type" "ssecvt") (set_attr "mode" "DF")]) -(define_insn "*extendsfdf2_i387" - [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m") - (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))] - "TARGET_80387 - && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" -{ - switch (which_alternative) - { - case 0: - return output_387_reg_move (insn, operands); - - case 1: - if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) - return "fstp%z0\t%y0"; - else - return "fst%z0\t%y0"; - - default: - gcc_unreachable (); - } -} - [(set_attr "type" "fmov") - (set_attr "mode" "SF,XF")]) - (define_expand "extendsfxf2" [(set (match_operand:XF 0 "nonimmediate_operand" "") (float_extend:XF (match_operand:SF 1 "general_operand" "")))] @@ -3605,21 +3571,12 @@ /* ??? Needed for compress_float_constant since all fp constants are LEGITIMATE_CONSTANT_P. */ if (GET_CODE (operands[1]) == CONST_DOUBLE) - { - if (standard_80387_constant_p (operands[1]) > 0) - { - operands[1] = simplify_const_unary_operation - (FLOAT_EXTEND, XFmode, operands[1], SFmode); - emit_move_insn_1 (operands[0], operands[1]); - DONE; - } - operands[1] = validize_mem (force_const_mem (SFmode, operands[1])); - } + operands[1] = validize_mem (force_const_mem (SFmode, operands[1])); if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[1] = force_reg (SFmode, operands[1]); }) -(define_insn "*extendsfxf2_i387" +(define_insn "*extendsfxf2_1" [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m") (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))] "TARGET_80387 @@ -3628,18 +3585,24 @@ switch (which_alternative) { case 0: - return output_387_reg_move (insn, operands); + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; case 1: /* There is no non-popping store to memory for XFmode. So if we need one, follow the store with a load. */ - if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) - return "fstp%z0\t%y0"; - else + if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) return "fstp%z0\t%y0\n\tfld%z0\t%y0"; + else + return "fstp%z0\t%y0"; default: - gcc_unreachable (); + abort (); } } [(set_attr "type" "fmov") @@ -3653,21 +3616,12 @@ /* ??? Needed for compress_float_constant since all fp constants are LEGITIMATE_CONSTANT_P. */ if (GET_CODE (operands[1]) == CONST_DOUBLE) - { - if (standard_80387_constant_p (operands[1]) > 0) - { - operands[1] = simplify_const_unary_operation - (FLOAT_EXTEND, XFmode, operands[1], DFmode); - emit_move_insn_1 (operands[0], operands[1]); - DONE; - } - operands[1] = validize_mem (force_const_mem (DFmode, operands[1])); - } + operands[1] = validize_mem (force_const_mem (DFmode, operands[1])); if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[1] = force_reg (DFmode, operands[1]); }) -(define_insn "*extenddfxf2_i387" +(define_insn "*extenddfxf2_1" [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m") (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,f")))] "TARGET_80387 @@ -3676,7 +3630,13 @@ switch (which_alternative) { case 0: - return output_387_reg_move (insn, operands); + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; case 1: /* There is no non-popping store to memory for XFmode. So if @@ -3687,7 +3647,7 @@ return "fstp%z0\t%y0"; default: - gcc_unreachable (); + abort (); } } [(set_attr "type" "fmov") @@ -3699,40 +3659,49 @@ ;; insn. So we pretend we can output to a reg in order to get better ;; register preferencing, but we really use a stack slot. -;; Conversion from DFmode to SFmode. - (define_expand "truncdfsf2" - [(set (match_operand:SF 0 "nonimmediate_operand" "") + [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") + (float_truncate:SF + (match_operand:DF 1 "register_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387 || TARGET_SSE2" + " + if (TARGET_80387) + operands[2] = assign_386_stack_local (SFmode, 0); + else + { + emit_insn (gen_truncdfsf2_sse_only (operands[0], operands[1])); + DONE; + } +") + +(define_insn "*truncdfsf2_1" + [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f#rx,?r#fx,?x#rf") (float_truncate:SF - (match_operand:DF 1 "nonimmediate_operand" "")))] - "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" + (match_operand:DF 1 "register_operand" "f,f,f,f"))) + (clobber (match_operand:SF 2 "memory_operand" "=X,m,m,m"))] + "TARGET_80387 && !TARGET_SSE2" { - if (MEM_P (operands[0]) && MEM_P (operands[1])) - operands[1] = force_reg (DFmode, operands[1]); - - if (TARGET_SSE2 && TARGET_SSE_MATH && !TARGET_MIX_SSE_I387) - ; - else if (flag_unsafe_math_optimizations) - ; - else + switch (which_alternative) { - rtx temp = assign_386_stack_local (SFmode, SLOT_TEMP); - emit_insn (gen_truncdfsf2_with_temp (operands[0], operands[1], temp)); - DONE; + case 0: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + default: + abort (); } -}) - -(define_expand "truncdfsf2_with_temp" - [(parallel [(set (match_operand:SF 0 "" "") - (float_truncate:SF (match_operand:DF 1 "" ""))) - (clobber (match_operand:SF 2 "" ""))])] - "") +} + [(set_attr "type" "fmov,multi,multi,multi") + (set_attr "mode" "SF,SF,SF,SF")]) -(define_insn "*truncdfsf_fast_mixed" - [(set (match_operand:SF 0 "nonimmediate_operand" "=m,f,Y") - (float_truncate:SF - (match_operand:DF 1 "nonimmediate_operand" "f ,f,Ym")))] - "TARGET_SSE2 && TARGET_MIX_SSE_I387 && flag_unsafe_math_optimizations" +(define_insn "*truncdfsf2_1_sse" + [(set (match_operand:SF 0 "nonimmediate_operand" "=*!m#fxr,?f#xr,?r#fx,?x#fr,Y#fr") + (float_truncate:SF + (match_operand:DF 1 "nonimmediate_operand" "f#Y,f#Y,f#Y,f#Y,mY#f"))) + (clobber (match_operand:SF 2 "memory_operand" "=X,m,m,m,X"))] + "TARGET_80387 && TARGET_SSE2 && !TARGET_SSE_PARTIAL_REGS_FOR_CVTSD2SS" { switch (which_alternative) { @@ -3741,43 +3710,21 @@ return "fstp%z0\t%y0"; else return "fst%z0\t%y0"; - case 1: - return output_387_reg_move (insn, operands); - case 2: - return "cvtsd2ss\t{%1, %0|%0, %1}"; + case 4: + return "#"; default: - gcc_unreachable (); + abort (); } } - [(set_attr "type" "fmov,fmov,ssecvt") - (set_attr "mode" "SF")]) - -;; Yes, this one doesn't depend on flag_unsafe_math_optimizations, -;; because nothing we do here is unsafe. -(define_insn "*truncdfsf_fast_sse" - [(set (match_operand:SF 0 "nonimmediate_operand" "=Y") - (float_truncate:SF - (match_operand:DF 1 "nonimmediate_operand" "Ym")))] - "TARGET_SSE2 && TARGET_SSE_MATH" - "cvtsd2ss\t{%1, %0|%0, %1}" - [(set_attr "type" "ssecvt") - (set_attr "mode" "SF")]) - -(define_insn "*truncdfsf_fast_i387" - [(set (match_operand:SF 0 "nonimmediate_operand" "=fm") - (float_truncate:SF - (match_operand:DF 1 "nonimmediate_operand" "f")))] - "TARGET_80387 && flag_unsafe_math_optimizations" - "* return output_387_reg_move (insn, operands);" - [(set_attr "type" "fmov") - (set_attr "mode" "SF")]) + [(set_attr "type" "fmov,multi,multi,multi,ssecvt") + (set_attr "mode" "SF,SF,SF,SF,DF")]) -(define_insn "*truncdfsf_mixed" - [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?fx*r,Y") +(define_insn "*truncdfsf2_1_sse_nooverlap" + [(set (match_operand:SF 0 "nonimmediate_operand" "=*!m,?f#rx,?r#fx,?x#rf,&Y") (float_truncate:SF - (match_operand:DF 1 "nonimmediate_operand" "f ,f ,Ym"))) - (clobber (match_operand:SF 2 "memory_operand" "=X,m ,X"))] - "TARGET_MIX_SSE_I387" + (match_operand:DF 1 "nonimmediate_operand" "f#Y,f#Y,f#Y,f#Y,mY#f"))) + (clobber (match_operand:SF 2 "memory_operand" "=X,m,m,m,X"))] + "TARGET_80387 && TARGET_SSE2 && TARGET_SSE_PARTIAL_REGS_FOR_CVTSD2SS" { switch (which_alternative) { @@ -3786,49 +3733,68 @@ return "fstp%z0\t%y0"; else return "fst%z0\t%y0"; - case 1: + case 4: return "#"; - case 2: - return "cvtsd2ss\t{%1, %0|%0, %1}"; default: - gcc_unreachable (); + abort (); } } - [(set_attr "type" "fmov,multi,ssecvt") - (set_attr "unit" "*,i387,*") - (set_attr "mode" "SF")]) + [(set_attr "type" "fmov,multi,multi,multi,ssecvt") + (set_attr "mode" "SF,SF,SF,SF,DF")]) -(define_insn "*truncdfsf_i387" - [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?fx*r") +(define_insn "*truncdfsf2_2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=Y,Y,!m") (float_truncate:SF - (match_operand:DF 1 "nonimmediate_operand" "f,f"))) - (clobber (match_operand:SF 2 "memory_operand" "=X,m"))] - "TARGET_80387" + (match_operand:DF 1 "nonimmediate_operand" "Y,mY,f#Y")))] + "TARGET_80387 && TARGET_SSE2 && !TARGET_SSE_PARTIAL_REGS_FOR_CVTSD2SS + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" { switch (which_alternative) { case 0: + case 1: + return "cvtsd2ss\t{%1, %0|%0, %1}"; + case 2: if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) return "fstp%z0\t%y0"; else return "fst%z0\t%y0"; - case 1: + default: + abort (); + } +} + [(set_attr "type" "ssecvt,ssecvt,fmov") + (set_attr "athlon_decode" "vector,double,*") + (set_attr "mode" "SF,SF,SF")]) + +(define_insn "*truncdfsf2_2_nooverlap" + [(set (match_operand:SF 0 "nonimmediate_operand" "=&Y,!m") + (float_truncate:SF + (match_operand:DF 1 "nonimmediate_operand" "mY,f")))] + "TARGET_80387 && TARGET_SSE2 && TARGET_SSE_PARTIAL_REGS_FOR_CVTSD2SS + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: return "#"; + case 1: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; default: - gcc_unreachable (); + abort (); } } - [(set_attr "type" "fmov,multi") - (set_attr "unit" "*,i387") - (set_attr "mode" "SF")]) + [(set_attr "type" "ssecvt,fmov") + (set_attr "mode" "DF,SF")]) -(define_insn "*truncdfsf2_i387_1" +(define_insn "*truncdfsf2_3" [(set (match_operand:SF 0 "memory_operand" "=m") (float_truncate:SF - (match_operand:DF 1 "register_operand" "f")))] - "TARGET_80387 - && !(TARGET_SSE2 && TARGET_SSE_MATH) - && !TARGET_MIX_SSE_I387" + (match_operand:DF 1 "register_operand" "f")))] + "TARGET_80387" { if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) return "fstp%z0\t%y0"; @@ -3838,19 +3804,94 @@ [(set_attr "type" "fmov") (set_attr "mode" "SF")]) +(define_insn "truncdfsf2_sse_only" + [(set (match_operand:SF 0 "register_operand" "=Y,Y") + (float_truncate:SF + (match_operand:DF 1 "nonimmediate_operand" "Y,mY")))] + "!TARGET_80387 && TARGET_SSE2 && !TARGET_SSE_PARTIAL_REGS_FOR_CVTSD2SS" + "cvtsd2ss\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "athlon_decode" "vector,double") + (set_attr "mode" "SF")]) + +(define_insn "*truncdfsf2_sse_only_nooverlap" + [(set (match_operand:SF 0 "register_operand" "=&Y") + (float_truncate:SF + (match_operand:DF 1 "nonimmediate_operand" "mY")))] + "!TARGET_80387 && TARGET_SSE2 && TARGET_SSE_PARTIAL_REGS_FOR_CVTSD2SS" + "#" + [(set_attr "type" "ssecvt") + (set_attr "mode" "DF")]) + +(define_split + [(set (match_operand:SF 0 "memory_operand" "") + (float_truncate:SF + (match_operand:DF 1 "register_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" ""))] + "TARGET_80387" + [(set (match_dup 0) (float_truncate:SF (match_dup 1)))] + "") + +; Avoid possible reformatting penalty on the destination by first +; zeroing it out (define_split [(set (match_operand:SF 0 "register_operand" "") (float_truncate:SF - (match_operand:DF 1 "fp_register_operand" ""))) + (match_operand:DF 1 "nonimmediate_operand" ""))) (clobber (match_operand 2 "" ""))] - "reload_completed" - [(set (match_dup 2) (match_dup 1)) - (set (match_dup 0) (match_dup 2))] + "TARGET_80387 && reload_completed + && SSE_REG_P (operands[0]) + && !STACK_REG_P (operands[1])" + [(const_int 0)] { - operands[1] = gen_rtx_REG (SFmode, true_regnum (operands[1])); + rtx src, dest; + if (!TARGET_SSE_PARTIAL_REGS_FOR_CVTSD2SS) + emit_insn (gen_truncdfsf2_sse_only (operands[0], operands[1])); + else + { + dest = simplify_gen_subreg (V4SFmode, operands[0], SFmode, 0); + src = simplify_gen_subreg (V2DFmode, operands[1], DFmode, 0); + /* simplify_gen_subreg refuses to widen memory references. */ + if (GET_CODE (src) == SUBREG) + alter_subreg (&src); + if (reg_overlap_mentioned_p (operands[0], operands[1])) + abort (); + emit_insn (gen_sse_clrv4sf (dest, CONST0_RTX (V4SFmode))); + emit_insn (gen_cvtsd2ss (dest, dest, src)); + } + DONE; }) -;; Conversion from XFmode to SFmode. +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float_truncate:SF + (match_operand:DF 1 "nonimmediate_operand" "")))] + "TARGET_80387 && reload_completed + && SSE_REG_P (operands[0]) && TARGET_SSE_PARTIAL_REGS_FOR_CVTSD2SS" + [(const_int 0)] +{ + rtx src, dest; + dest = simplify_gen_subreg (V4SFmode, operands[0], SFmode, 0); + src = simplify_gen_subreg (V2DFmode, operands[1], DFmode, 0); + /* simplify_gen_subreg refuses to widen memory references. */ + if (GET_CODE (src) == SUBREG) + alter_subreg (&src); + if (reg_overlap_mentioned_p (operands[0], operands[1])) + abort (); + emit_insn (gen_sse_clrv4sf (dest, CONST0_RTX (V4SFmode))); + emit_insn (gen_cvtsd2ss (dest, dest, src)); + DONE; +}) + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float_truncate:SF + (match_operand:DF 1 "fp_register_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) (float_truncate:SF (match_dup 1))) + (set (match_dup 0) (match_dup 2))] + "") (define_expand "truncxfsf2" [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") @@ -3858,64 +3899,30 @@ (match_operand:XF 1 "register_operand" ""))) (clobber (match_dup 2))])] "TARGET_80387" -{ - if (flag_unsafe_math_optimizations) - { - rtx reg = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (SFmode); - emit_insn (gen_truncxfsf2_i387_noop (reg, operands[1])); - if (reg != operands[0]) - emit_move_insn (operands[0], reg); - DONE; - } - else - operands[2] = assign_386_stack_local (SFmode, SLOT_TEMP); -}) + "operands[2] = assign_386_stack_local (SFmode, 0);") -(define_insn "*truncxfsf2_mixed" - [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f,?r,?x") +(define_insn "*truncxfsf2_1" + [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f#rx,?r#fx,?x#rf") (float_truncate:SF (match_operand:XF 1 "register_operand" "f,f,f,f"))) (clobber (match_operand:SF 2 "memory_operand" "=X,m,m,m"))] - "TARGET_MIX_SSE_I387" -{ - gcc_assert (!which_alternative); - if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) - return "fstp%z0\t%y0"; - else - return "fst%z0\t%y0"; -} - [(set_attr "type" "fmov,multi,multi,multi") - (set_attr "unit" "*,i387,i387,i387") - (set_attr "mode" "SF")]) - -(define_insn "truncxfsf2_i387_noop" - [(set (match_operand:SF 0 "register_operand" "=f") - (float_truncate:SF (match_operand:XF 1 "register_operand" "f")))] - "TARGET_80387 && flag_unsafe_math_optimizations" -{ - return output_387_reg_move (insn, operands); -} - [(set_attr "type" "fmov") - (set_attr "mode" "SF")]) - -(define_insn "*truncxfsf2_i387" - [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f,?r") - (float_truncate:SF - (match_operand:XF 1 "register_operand" "f,f,f"))) - (clobber (match_operand:SF 2 "memory_operand" "=X,m,m"))] "TARGET_80387" { - gcc_assert (!which_alternative); - if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) - return "fstp%z0\t%y0"; - else - return "fst%z0\t%y0"; + switch (which_alternative) + { + case 0: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + default: + abort(); + } } - [(set_attr "type" "fmov,multi,multi") - (set_attr "unit" "*,i387,i387") + [(set_attr "type" "fmov,multi,multi,multi") (set_attr "mode" "SF")]) -(define_insn "*truncxfsf2_i387_1" +(define_insn "*truncxfsf2_2" [(set (match_operand:SF 0 "memory_operand" "=m") (float_truncate:SF (match_operand:XF 1 "register_operand" "f")))] @@ -3930,90 +3937,55 @@ (set_attr "mode" "SF")]) (define_split - [(set (match_operand:SF 0 "register_operand" "") + [(set (match_operand:SF 0 "memory_operand" "") (float_truncate:SF (match_operand:XF 1 "register_operand" ""))) (clobber (match_operand:SF 2 "memory_operand" ""))] - "TARGET_80387 && reload_completed" - [(set (match_dup 2) (float_truncate:SF (match_dup 1))) - (set (match_dup 0) (match_dup 2))] + "TARGET_80387" + [(set (match_dup 0) (float_truncate:SF (match_dup 1)))] "") (define_split - [(set (match_operand:SF 0 "memory_operand" "") + [(set (match_operand:SF 0 "register_operand" "") (float_truncate:SF (match_operand:XF 1 "register_operand" ""))) (clobber (match_operand:SF 2 "memory_operand" ""))] - "TARGET_80387" - [(set (match_dup 0) (float_truncate:SF (match_dup 1)))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) (float_truncate:SF (match_dup 1))) + (set (match_dup 0) (match_dup 2))] "") -;; Conversion from XFmode to DFmode. - (define_expand "truncxfdf2" [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "") (float_truncate:DF (match_operand:XF 1 "register_operand" ""))) (clobber (match_dup 2))])] "TARGET_80387" -{ - if (flag_unsafe_math_optimizations) - { - rtx reg = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (DFmode); - emit_insn (gen_truncxfdf2_i387_noop (reg, operands[1])); - if (reg != operands[0]) - emit_move_insn (operands[0], reg); - DONE; - } - else - operands[2] = assign_386_stack_local (DFmode, SLOT_TEMP); -}) + "operands[2] = assign_386_stack_local (DFmode, 0);") -(define_insn "*truncxfdf2_mixed" - [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f,?r,?Y") +(define_insn "*truncxfdf2_1" + [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f#rY,?r#fY,?Y#rf") (float_truncate:DF (match_operand:XF 1 "register_operand" "f,f,f,f"))) (clobber (match_operand:DF 2 "memory_operand" "=X,m,m,m"))] - "TARGET_SSE2 && TARGET_MIX_SSE_I387" -{ - gcc_assert (!which_alternative); - if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) - return "fstp%z0\t%y0"; - else - return "fst%z0\t%y0"; -} - [(set_attr "type" "fmov,multi,multi,multi") - (set_attr "unit" "*,i387,i387,i387") - (set_attr "mode" "DF")]) - -(define_insn "truncxfdf2_i387_noop" - [(set (match_operand:DF 0 "register_operand" "=f") - (float_truncate:DF (match_operand:XF 1 "register_operand" "f")))] - "TARGET_80387 && flag_unsafe_math_optimizations" -{ - return output_387_reg_move (insn, operands); -} - [(set_attr "type" "fmov") - (set_attr "mode" "DF")]) - -(define_insn "*truncxfdf2_i387" - [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f,?r") - (float_truncate:DF - (match_operand:XF 1 "register_operand" "f,f,f"))) - (clobber (match_operand:DF 2 "memory_operand" "=X,m,m"))] "TARGET_80387" { - gcc_assert (!which_alternative); - if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) - return "fstp%z0\t%y0"; - else - return "fst%z0\t%y0"; + switch (which_alternative) + { + case 0: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + default: + abort(); + } + abort (); } - [(set_attr "type" "fmov,multi,multi") - (set_attr "unit" "*,i387,i387") + [(set_attr "type" "fmov,multi,multi,multi") (set_attr "mode" "DF")]) -(define_insn "*truncxfdf2_i387_1" +(define_insn "*truncxfdf2_2" [(set (match_operand:DF 0 "memory_operand" "=m") (float_truncate:DF (match_operand:XF 1 "register_operand" "f")))] @@ -4028,411 +4000,463 @@ (set_attr "mode" "DF")]) (define_split - [(set (match_operand:DF 0 "register_operand" "") + [(set (match_operand:DF 0 "memory_operand" "") (float_truncate:DF (match_operand:XF 1 "register_operand" ""))) (clobber (match_operand:DF 2 "memory_operand" ""))] - "TARGET_80387 && reload_completed" - [(set (match_dup 2) (float_truncate:DF (match_dup 1))) - (set (match_dup 0) (match_dup 2))] + "TARGET_80387" + [(set (match_dup 0) (float_truncate:DF (match_dup 1)))] "") (define_split - [(set (match_operand:DF 0 "memory_operand" "") + [(set (match_operand:DF 0 "register_operand" "") (float_truncate:DF (match_operand:XF 1 "register_operand" ""))) (clobber (match_operand:DF 2 "memory_operand" ""))] - "TARGET_80387" - [(set (match_dup 0) (float_truncate:DF (match_dup 1)))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) (float_truncate:DF (match_dup 1))) + (set (match_dup 0) (match_dup 2))] "") + +;; %%% Break up all these bad boys. + ;; Signed conversion to DImode. (define_expand "fix_truncxfdi2" - [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") - (fix:DI (match_operand:XF 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (match_operand:XF 1 "register_operand" "")))] "TARGET_80387" + "") + +(define_expand "fix_truncdfdi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (match_operand:DF 1 "register_operand" "")))] + "TARGET_80387 || (TARGET_SSE2 && TARGET_64BIT)" { - if (TARGET_FISTTP) + if (TARGET_64BIT && TARGET_SSE2) { - emit_insn (gen_fix_truncdi_fisttp_i387_1 (operands[0], operands[1])); + rtx out = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (DImode); + emit_insn (gen_fix_truncdfdi_sse (out, operands[1])); + if (out != operands[0]) + emit_move_insn (operands[0], out); DONE; } }) -(define_expand "fix_trunc<mode>di2" - [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") - (fix:DI (match_operand:SSEMODEF 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_80387 || (TARGET_64BIT && SSE_FLOAT_MODE_P (<MODE>mode))" +(define_expand "fix_truncsfdi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (match_operand:SF 1 "register_operand" "")))] + "TARGET_80387 || (TARGET_SSE && TARGET_64BIT)" { - if (TARGET_FISTTP - && !(TARGET_64BIT && SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)) - { - emit_insn (gen_fix_truncdi_fisttp_i387_1 (operands[0], operands[1])); - DONE; - } - if (TARGET_64BIT && SSE_FLOAT_MODE_P (<MODE>mode)) + if (TARGET_SSE && TARGET_64BIT) { rtx out = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (DImode); - emit_insn (gen_fix_trunc<mode>di_sse (out, operands[1])); + emit_insn (gen_fix_truncsfdi_sse (out, operands[1])); if (out != operands[0]) emit_move_insn (operands[0], out); DONE; } }) +;; See the comments in i386.h near OPTIMIZE_MODE_SWITCHING for the description +;; of the machinery. +(define_insn_and_split "*fix_truncdi_1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r") + (fix:DI (match_operand 1 "register_operand" "f,f")))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !reload_completed && !reload_in_progress + && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)" + "#" + "&& 1" + [(const_int 0)] +{ + ix86_optimize_mode_switching = 1; + operands[2] = assign_386_stack_local (HImode, 1); + operands[3] = assign_386_stack_local (HImode, 2); + if (memory_operand (operands[0], VOIDmode)) + emit_insn (gen_fix_truncdi_memory (operands[0], operands[1], + operands[2], operands[3])); + else + { + operands[4] = assign_386_stack_local (DImode, 0); + emit_insn (gen_fix_truncdi_nomemory (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + } + DONE; +} + [(set_attr "type" "fistp") + (set_attr "mode" "DI")]) + +(define_insn "fix_truncdi_nomemory" + [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r") + (fix:DI (match_operand 1 "register_operand" "f,f"))) + (use (match_operand:HI 2 "memory_operand" "m,m")) + (use (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:DI 4 "memory_operand" "=m,m")) + (clobber (match_scratch:DF 5 "=&1f,&1f"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)" + "#" + [(set_attr "type" "fistp") + (set_attr "mode" "DI")]) + +(define_insn "fix_truncdi_memory" + [(set (match_operand:DI 0 "memory_operand" "=m") + (fix:DI (match_operand 1 "register_operand" "f"))) + (use (match_operand:HI 2 "memory_operand" "m")) + (use (match_operand:HI 3 "memory_operand" "m")) + (clobber (match_scratch:DF 4 "=&1f"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)" + "* operands[5] = operands[4]; return output_fix_trunc (insn, operands);" + [(set_attr "type" "fistp") + (set_attr "mode" "DI")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (fix:DI (match_operand 1 "register_operand" ""))) + (use (match_operand:HI 2 "memory_operand" "")) + (use (match_operand:HI 3 "memory_operand" "")) + (clobber (match_operand:DI 4 "memory_operand" "")) + (clobber (match_scratch 5 ""))] + "reload_completed" + [(parallel [(set (match_dup 4) (fix:DI (match_dup 1))) + (use (match_dup 2)) + (use (match_dup 3)) + (clobber (match_dup 5))]) + (set (match_dup 0) (match_dup 4))] + "") + +(define_split + [(set (match_operand:DI 0 "memory_operand" "") + (fix:DI (match_operand 1 "register_operand" ""))) + (use (match_operand:HI 2 "memory_operand" "")) + (use (match_operand:HI 3 "memory_operand" "")) + (clobber (match_operand:DI 4 "memory_operand" "")) + (clobber (match_scratch 5 ""))] + "reload_completed" + [(parallel [(set (match_dup 0) (fix:DI (match_dup 1))) + (use (match_dup 2)) + (use (match_dup 3)) + (clobber (match_dup 5))])] + "") + +;; When SSE available, it is always faster to use it! +(define_insn "fix_truncsfdi_sse" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (fix:DI (match_operand:SF 1 "nonimmediate_operand" "x,xm")))] + "TARGET_64BIT && TARGET_SSE" + "cvttss2si{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "sseicvt") + (set_attr "mode" "SF") + (set_attr "athlon_decode" "double,vector")]) + +;; Avoid vector decoded form of the instruction. +(define_peephole2 + [(match_scratch:SF 2 "x") + (set (match_operand:DI 0 "register_operand" "") + (fix:DI (match_operand:SF 1 "memory_operand" "")))] + "TARGET_K8 && !optimize_size" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (fix:DI (match_dup 2)))] + "") + +(define_insn "fix_truncdfdi_sse" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (fix:DI (match_operand:DF 1 "nonimmediate_operand" "Y,Ym")))] + "TARGET_64BIT && TARGET_SSE2" + "cvttsd2si{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "sseicvt,sseicvt") + (set_attr "mode" "DF") + (set_attr "athlon_decode" "double,vector")]) + +;; Avoid vector decoded form of the instruction. +(define_peephole2 + [(match_scratch:DF 2 "Y") + (set (match_operand:DI 0 "register_operand" "") + (fix:DI (match_operand:DF 1 "memory_operand" "")))] + "TARGET_K8 && !optimize_size" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (fix:DI (match_dup 2)))] + "") + ;; Signed conversion to SImode. (define_expand "fix_truncxfsi2" - [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") - (fix:SI (match_operand:XF 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (fix:SI (match_operand:XF 1 "register_operand" "")))] "TARGET_80387" + "") + +(define_expand "fix_truncdfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (fix:SI (match_operand:DF 1 "register_operand" "")))] + "TARGET_80387 || TARGET_SSE2" { - if (TARGET_FISTTP) + if (TARGET_SSE2) { - emit_insn (gen_fix_truncsi_fisttp_i387_1 (operands[0], operands[1])); + rtx out = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (SImode); + emit_insn (gen_fix_truncdfsi_sse (out, operands[1])); + if (out != operands[0]) + emit_move_insn (operands[0], out); DONE; } }) -(define_expand "fix_trunc<mode>si2" - [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") - (fix:SI (match_operand:SSEMODEF 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_80387 || SSE_FLOAT_MODE_P (<MODE>mode)" +(define_expand "fix_truncsfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (fix:SI (match_operand:SF 1 "register_operand" "")))] + "TARGET_80387 || TARGET_SSE" { - if (TARGET_FISTTP - && !(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)) - { - emit_insn (gen_fix_truncsi_fisttp_i387_1 (operands[0], operands[1])); - DONE; - } - if (SSE_FLOAT_MODE_P (<MODE>mode)) + if (TARGET_SSE) { rtx out = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (SImode); - emit_insn (gen_fix_trunc<mode>si_sse (out, operands[1])); + emit_insn (gen_fix_truncsfsi_sse (out, operands[1])); if (out != operands[0]) emit_move_insn (operands[0], out); DONE; } }) -;; Signed conversion to HImode. - -(define_expand "fix_trunc<mode>hi2" - [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "") - (fix:HI (match_operand:X87MODEF 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_80387 - && !(SSE_FLOAT_MODE_P (<MODE>mode) && (!TARGET_FISTTP || TARGET_SSE_MATH))" +;; See the comments in i386.h near OPTIMIZE_MODE_SWITCHING for the description +;; of the machinery. +(define_insn_and_split "*fix_truncsi_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r") + (fix:SI (match_operand 1 "register_operand" "f,f")))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !reload_completed && !reload_in_progress + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" + "#" + "&& 1" + [(const_int 0)] { - if (TARGET_FISTTP) - { - emit_insn (gen_fix_trunchi_fisttp_i387_1 (operands[0], operands[1])); - DONE; - } -}) + ix86_optimize_mode_switching = 1; + operands[2] = assign_386_stack_local (HImode, 1); + operands[3] = assign_386_stack_local (HImode, 2); + if (memory_operand (operands[0], VOIDmode)) + emit_insn (gen_fix_truncsi_memory (operands[0], operands[1], + operands[2], operands[3])); + else + { + operands[4] = assign_386_stack_local (SImode, 0); + emit_insn (gen_fix_truncsi_nomemory (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + } + DONE; +} + [(set_attr "type" "fistp") + (set_attr "mode" "SI")]) -;; When SSE is available, it is always faster to use it! -(define_insn "fix_truncsfdi_sse" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (fix:DI (match_operand:SF 1 "nonimmediate_operand" "x,xm")))] - "TARGET_64BIT && TARGET_SSE && (!TARGET_FISTTP || TARGET_SSE_MATH)" - "cvttss2si{q}\t{%1, %0|%0, %1}" - [(set_attr "type" "sseicvt") - (set_attr "mode" "SF") - (set_attr "athlon_decode" "double,vector")]) +(define_insn "fix_truncsi_nomemory" + [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r") + (fix:SI (match_operand 1 "register_operand" "f,f"))) + (use (match_operand:HI 2 "memory_operand" "m,m")) + (use (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:SI 4 "memory_operand" "=m,m"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" + "#" + [(set_attr "type" "fistp") + (set_attr "mode" "SI")]) -(define_insn "fix_truncdfdi_sse" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (fix:DI (match_operand:DF 1 "nonimmediate_operand" "Y,Ym")))] - "TARGET_64BIT && TARGET_SSE2 && (!TARGET_FISTTP || TARGET_SSE_MATH)" - "cvttsd2si{q}\t{%1, %0|%0, %1}" - [(set_attr "type" "sseicvt") - (set_attr "mode" "DF") - (set_attr "athlon_decode" "double,vector")]) +(define_insn "fix_truncsi_memory" + [(set (match_operand:SI 0 "memory_operand" "=m") + (fix:SI (match_operand 1 "register_operand" "f"))) + (use (match_operand:HI 2 "memory_operand" "m")) + (use (match_operand:HI 3 "memory_operand" "m"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" + "* return output_fix_trunc (insn, operands);" + [(set_attr "type" "fistp") + (set_attr "mode" "SI")]) +;; When SSE available, it is always faster to use it! (define_insn "fix_truncsfsi_sse" [(set (match_operand:SI 0 "register_operand" "=r,r") (fix:SI (match_operand:SF 1 "nonimmediate_operand" "x,xm")))] - "TARGET_SSE && (!TARGET_FISTTP || TARGET_SSE_MATH)" + "TARGET_SSE" "cvttss2si\t{%1, %0|%0, %1}" [(set_attr "type" "sseicvt") (set_attr "mode" "DF") (set_attr "athlon_decode" "double,vector")]) +;; Avoid vector decoded form of the instruction. +(define_peephole2 + [(match_scratch:SF 2 "x") + (set (match_operand:SI 0 "register_operand" "") + (fix:SI (match_operand:SF 1 "memory_operand" "")))] + "TARGET_K8 && !optimize_size" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (fix:SI (match_dup 2)))] + "") + (define_insn "fix_truncdfsi_sse" [(set (match_operand:SI 0 "register_operand" "=r,r") (fix:SI (match_operand:DF 1 "nonimmediate_operand" "Y,Ym")))] - "TARGET_SSE2 && (!TARGET_FISTTP || TARGET_SSE_MATH)" + "TARGET_SSE2" "cvttsd2si\t{%1, %0|%0, %1}" [(set_attr "type" "sseicvt") (set_attr "mode" "DF") (set_attr "athlon_decode" "double,vector")]) -;; Avoid vector decoded forms of the instruction. +;; Avoid vector decoded form of the instruction. (define_peephole2 [(match_scratch:DF 2 "Y") - (set (match_operand:SSEMODEI24 0 "register_operand" "") - (fix:SSEMODEI24 (match_operand:DF 1 "memory_operand" "")))] - "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size" + (set (match_operand:SI 0 "register_operand" "") + (fix:SI (match_operand:DF 1 "memory_operand" "")))] + "TARGET_K8 && !optimize_size" [(set (match_dup 2) (match_dup 1)) - (set (match_dup 0) (fix:SSEMODEI24 (match_dup 2)))] + (set (match_dup 0) (fix:SI (match_dup 2)))] "") -(define_peephole2 - [(match_scratch:SF 2 "x") - (set (match_operand:SSEMODEI24 0 "register_operand" "") - (fix:SSEMODEI24 (match_operand:SF 1 "memory_operand" "")))] - "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size" - [(set (match_dup 2) (match_dup 1)) - (set (match_dup 0) (fix:SSEMODEI24 (match_dup 2)))] +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (fix:SI (match_operand 1 "register_operand" ""))) + (use (match_operand:HI 2 "memory_operand" "")) + (use (match_operand:HI 3 "memory_operand" "")) + (clobber (match_operand:SI 4 "memory_operand" ""))] + "reload_completed" + [(parallel [(set (match_dup 4) (fix:SI (match_dup 1))) + (use (match_dup 2)) + (use (match_dup 3))]) + (set (match_dup 0) (match_dup 4))] "") -(define_insn_and_split "fix_trunc<mode>_fisttp_i387_1" - [(set (match_operand:X87MODEI 0 "nonimmediate_operand" "=m,?r") - (fix:X87MODEI (match_operand 1 "register_operand" "f,f")))] - "TARGET_FISTTP - && FLOAT_MODE_P (GET_MODE (operands[1])) - && !((SSE_FLOAT_MODE_P (GET_MODE (operands[1])) - && (TARGET_64BIT || <MODE>mode != DImode)) - && TARGET_SSE_MATH) - && !(reload_completed || reload_in_progress)" - "#" - "&& 1" - [(const_int 0)] -{ - if (memory_operand (operands[0], VOIDmode)) - emit_insn (gen_fix_trunc<mode>_i387_fisttp (operands[0], operands[1])); - else - { - operands[2] = assign_386_stack_local (<MODE>mode, SLOT_TEMP); - emit_insn (gen_fix_trunc<mode>_i387_fisttp_with_temp (operands[0], - operands[1], - operands[2])); - } - DONE; -} - [(set_attr "type" "fisttp") - (set_attr "mode" "<MODE>")]) - -(define_insn "fix_trunc<mode>_i387_fisttp" - [(set (match_operand:X87MODEI 0 "memory_operand" "=m") - (fix:X87MODEI (match_operand 1 "register_operand" "f"))) - (clobber (match_scratch:XF 2 "=&1f"))] - "TARGET_FISTTP - && FLOAT_MODE_P (GET_MODE (operands[1])) - && !((SSE_FLOAT_MODE_P (GET_MODE (operands[1])) - && (TARGET_64BIT || <MODE>mode != DImode)) - && TARGET_SSE_MATH)" - "* return output_fix_trunc (insn, operands, 1);" - [(set_attr "type" "fisttp") - (set_attr "mode" "<MODE>")]) - -(define_insn "fix_trunc<mode>_i387_fisttp_with_temp" - [(set (match_operand:X87MODEI 0 "nonimmediate_operand" "=m,?r") - (fix:X87MODEI (match_operand 1 "register_operand" "f,f"))) - (clobber (match_operand:X87MODEI 2 "memory_operand" "=m,m")) - (clobber (match_scratch:XF 3 "=&1f,&1f"))] - "TARGET_FISTTP - && FLOAT_MODE_P (GET_MODE (operands[1])) - && !((SSE_FLOAT_MODE_P (GET_MODE (operands[1])) - && (TARGET_64BIT || <MODE>mode != DImode)) - && TARGET_SSE_MATH)" - "#" - [(set_attr "type" "fisttp") - (set_attr "mode" "<MODE>")]) - -(define_split - [(set (match_operand:X87MODEI 0 "register_operand" "") - (fix:X87MODEI (match_operand 1 "register_operand" ""))) - (clobber (match_operand:X87MODEI 2 "memory_operand" "")) - (clobber (match_scratch 3 ""))] +(define_split + [(set (match_operand:SI 0 "memory_operand" "") + (fix:SI (match_operand 1 "register_operand" ""))) + (use (match_operand:HI 2 "memory_operand" "")) + (use (match_operand:HI 3 "memory_operand" "")) + (clobber (match_operand:SI 4 "memory_operand" ""))] "reload_completed" - [(parallel [(set (match_dup 2) (fix:X87MODEI (match_dup 1))) - (clobber (match_dup 3))]) - (set (match_dup 0) (match_dup 2))] + [(parallel [(set (match_dup 0) (fix:SI (match_dup 1))) + (use (match_dup 2)) + (use (match_dup 3))])] "") -(define_split - [(set (match_operand:X87MODEI 0 "memory_operand" "") - (fix:X87MODEI (match_operand 1 "register_operand" ""))) - (clobber (match_operand:X87MODEI 2 "memory_operand" "")) - (clobber (match_scratch 3 ""))] - "reload_completed" - [(parallel [(set (match_dup 0) (fix:X87MODEI (match_dup 1))) - (clobber (match_dup 3))])] +;; Signed conversion to HImode. + +(define_expand "fix_truncxfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (fix:HI (match_operand:XF 1 "register_operand" "")))] + "TARGET_80387" + "") + +(define_expand "fix_truncdfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (fix:HI (match_operand:DF 1 "register_operand" "")))] + "TARGET_80387 && !TARGET_SSE2" + "") + +(define_expand "fix_truncsfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (fix:HI (match_operand:SF 1 "register_operand" "")))] + "TARGET_80387 && !TARGET_SSE" "") ;; See the comments in i386.h near OPTIMIZE_MODE_SWITCHING for the description -;; of the machinery. Please note the clobber of FLAGS_REG. In i387 control -;; word calculation (inserted by LCM in mode switching pass) a FLAGS_REG -;; clobbering insns can be used. Look at emit_i387_cw_initialization () -;; function in i386.c. -(define_insn_and_split "*fix_trunc<mode>_i387_1" - [(set (match_operand:X87MODEI 0 "nonimmediate_operand" "=m,?r") - (fix:X87MODEI (match_operand 1 "register_operand" "f,f"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_80387 && !TARGET_FISTTP - && FLOAT_MODE_P (GET_MODE (operands[1])) - && !(SSE_FLOAT_MODE_P (GET_MODE (operands[1])) - && (TARGET_64BIT || <MODE>mode != DImode)) - && !(reload_completed || reload_in_progress)" +;; of the machinery. +(define_insn_and_split "*fix_trunchi_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=m,?r") + (fix:HI (match_operand 1 "register_operand" "f,f")))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !reload_completed && !reload_in_progress + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" "#" - "&& 1" + "" [(const_int 0)] { - ix86_optimize_mode_switching[I387_TRUNC] = 1; - - operands[2] = assign_386_stack_local (HImode, SLOT_CW_STORED); - operands[3] = assign_386_stack_local (HImode, SLOT_CW_TRUNC); + ix86_optimize_mode_switching = 1; + operands[2] = assign_386_stack_local (HImode, 1); + operands[3] = assign_386_stack_local (HImode, 2); if (memory_operand (operands[0], VOIDmode)) - emit_insn (gen_fix_trunc<mode>_i387 (operands[0], operands[1], - operands[2], operands[3])); + emit_insn (gen_fix_trunchi_memory (operands[0], operands[1], + operands[2], operands[3])); else { - operands[4] = assign_386_stack_local (<MODE>mode, SLOT_TEMP); - emit_insn (gen_fix_trunc<mode>_i387_with_temp (operands[0], operands[1], - operands[2], operands[3], - operands[4])); + operands[4] = assign_386_stack_local (HImode, 0); + emit_insn (gen_fix_trunchi_nomemory (operands[0], operands[1], + operands[2], operands[3], + operands[4])); } DONE; } [(set_attr "type" "fistp") - (set_attr "i387_cw" "trunc") - (set_attr "mode" "<MODE>")]) - -(define_insn "fix_truncdi_i387" - [(set (match_operand:DI 0 "memory_operand" "=m") - (fix:DI (match_operand 1 "register_operand" "f"))) - (use (match_operand:HI 2 "memory_operand" "m")) - (use (match_operand:HI 3 "memory_operand" "m")) - (clobber (match_scratch:XF 4 "=&1f"))] - "TARGET_80387 && !TARGET_FISTTP - && FLOAT_MODE_P (GET_MODE (operands[1])) - && !(TARGET_64BIT && SSE_FLOAT_MODE_P (GET_MODE (operands[1])))" - "* return output_fix_trunc (insn, operands, 0);" - [(set_attr "type" "fistp") - (set_attr "i387_cw" "trunc") - (set_attr "mode" "DI")]) + (set_attr "mode" "HI")]) -(define_insn "fix_truncdi_i387_with_temp" - [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r") - (fix:DI (match_operand 1 "register_operand" "f,f"))) +(define_insn "fix_trunchi_nomemory" + [(set (match_operand:HI 0 "nonimmediate_operand" "=m,?r") + (fix:HI (match_operand 1 "register_operand" "f,f"))) (use (match_operand:HI 2 "memory_operand" "m,m")) (use (match_operand:HI 3 "memory_operand" "m,m")) - (clobber (match_operand:DI 4 "memory_operand" "=m,m")) - (clobber (match_scratch:XF 5 "=&1f,&1f"))] - "TARGET_80387 && !TARGET_FISTTP - && FLOAT_MODE_P (GET_MODE (operands[1])) - && !(TARGET_64BIT && SSE_FLOAT_MODE_P (GET_MODE (operands[1])))" + (clobber (match_operand:HI 4 "memory_operand" "=m,m"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" "#" [(set_attr "type" "fistp") - (set_attr "i387_cw" "trunc") - (set_attr "mode" "DI")]) - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (fix:DI (match_operand 1 "register_operand" ""))) - (use (match_operand:HI 2 "memory_operand" "")) - (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:DI 4 "memory_operand" "")) - (clobber (match_scratch 5 ""))] - "reload_completed" - [(parallel [(set (match_dup 4) (fix:DI (match_dup 1))) - (use (match_dup 2)) - (use (match_dup 3)) - (clobber (match_dup 5))]) - (set (match_dup 0) (match_dup 4))] - "") - -(define_split - [(set (match_operand:DI 0 "memory_operand" "") - (fix:DI (match_operand 1 "register_operand" ""))) - (use (match_operand:HI 2 "memory_operand" "")) - (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:DI 4 "memory_operand" "")) - (clobber (match_scratch 5 ""))] - "reload_completed" - [(parallel [(set (match_dup 0) (fix:DI (match_dup 1))) - (use (match_dup 2)) - (use (match_dup 3)) - (clobber (match_dup 5))])] - "") + (set_attr "mode" "HI")]) -(define_insn "fix_trunc<mode>_i387" - [(set (match_operand:X87MODEI12 0 "memory_operand" "=m") - (fix:X87MODEI12 (match_operand 1 "register_operand" "f"))) +(define_insn "fix_trunchi_memory" + [(set (match_operand:HI 0 "memory_operand" "=m") + (fix:HI (match_operand 1 "register_operand" "f"))) (use (match_operand:HI 2 "memory_operand" "m")) (use (match_operand:HI 3 "memory_operand" "m"))] - "TARGET_80387 && !TARGET_FISTTP - && FLOAT_MODE_P (GET_MODE (operands[1])) + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" - "* return output_fix_trunc (insn, operands, 0);" + "* return output_fix_trunc (insn, operands);" [(set_attr "type" "fistp") - (set_attr "i387_cw" "trunc") - (set_attr "mode" "<MODE>")]) - -(define_insn "fix_trunc<mode>_i387_with_temp" - [(set (match_operand:X87MODEI12 0 "nonimmediate_operand" "=m,?r") - (fix:X87MODEI12 (match_operand 1 "register_operand" "f,f"))) - (use (match_operand:HI 2 "memory_operand" "m,m")) - (use (match_operand:HI 3 "memory_operand" "m,m")) - (clobber (match_operand:X87MODEI12 4 "memory_operand" "=m,m"))] - "TARGET_80387 && !TARGET_FISTTP - && FLOAT_MODE_P (GET_MODE (operands[1])) - && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" - "#" - [(set_attr "type" "fistp") - (set_attr "i387_cw" "trunc") - (set_attr "mode" "<MODE>")]) + (set_attr "mode" "HI")]) (define_split - [(set (match_operand:X87MODEI12 0 "register_operand" "") - (fix:X87MODEI12 (match_operand 1 "register_operand" ""))) + [(set (match_operand:HI 0 "memory_operand" "") + (fix:HI (match_operand 1 "register_operand" ""))) (use (match_operand:HI 2 "memory_operand" "")) (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:X87MODEI12 4 "memory_operand" ""))] + (clobber (match_operand:HI 4 "memory_operand" ""))] "reload_completed" - [(parallel [(set (match_dup 4) (fix:X87MODEI12 (match_dup 1))) + [(parallel [(set (match_dup 0) (fix:HI (match_dup 1))) (use (match_dup 2)) - (use (match_dup 3))]) - (set (match_dup 0) (match_dup 4))] + (use (match_dup 3))])] "") (define_split - [(set (match_operand:X87MODEI12 0 "memory_operand" "") - (fix:X87MODEI12 (match_operand 1 "register_operand" ""))) + [(set (match_operand:HI 0 "register_operand" "") + (fix:HI (match_operand 1 "register_operand" ""))) (use (match_operand:HI 2 "memory_operand" "")) (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:X87MODEI12 4 "memory_operand" ""))] + (clobber (match_operand:HI 4 "memory_operand" ""))] "reload_completed" - [(parallel [(set (match_dup 0) (fix:X87MODEI12 (match_dup 1))) + [(parallel [(set (match_dup 4) (fix:HI (match_dup 1))) (use (match_dup 2)) - (use (match_dup 3))])] + (use (match_dup 3)) + (clobber (match_dup 4))]) + (set (match_dup 0) (match_dup 4))] "") +;; %% Not used yet. (define_insn "x86_fnstcw_1" [(set (match_operand:HI 0 "memory_operand" "=m") - (unspec:HI [(reg:HI FPSR_REG)] UNSPEC_FSTCW))] + (unspec:HI [(reg:HI 18)] UNSPEC_FSTCW))] "TARGET_80387" "fnstcw\t%0" [(set_attr "length" "2") (set_attr "mode" "HI") - (set_attr "unit" "i387")]) + (set_attr "unit" "i387") + (set_attr "ppro_uops" "few")]) (define_insn "x86_fldcw_1" - [(set (reg:HI FPSR_REG) + [(set (reg:HI 18) (unspec:HI [(match_operand:HI 0 "memory_operand" "m")] UNSPEC_FLDCW))] "TARGET_80387" "fldcw\t%0" [(set_attr "length" "2") (set_attr "mode" "HI") (set_attr "unit" "i387") - (set_attr "athlon_decode" "vector")]) + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) ;; Conversion between fixed point and floating point. @@ -4442,9 +4466,9 @@ (define_expand "floathisf2" [(set (match_operand:SF 0 "register_operand" "") (float:SF (match_operand:HI 1 "nonimmediate_operand" "")))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_SSE || TARGET_80387" { - if (TARGET_SSE_MATH) + if (TARGET_SSE && TARGET_SSE_MATH) { emit_insn (gen_floatsisf2 (operands[0], convert_to_mode (SImode, operands[1], 0))); @@ -4452,28 +4476,27 @@ } }) -(define_insn "*floathisf2_i387" +(define_insn "*floathisf2_1" [(set (match_operand:SF 0 "register_operand" "=f,f") - (float:SF (match_operand:HI 1 "nonimmediate_operand" "m,?r")))] - "TARGET_80387 && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387)" + (float:SF (match_operand:HI 1 "nonimmediate_operand" "m,r")))] + "TARGET_80387 && (!TARGET_SSE || !TARGET_SSE_MATH)" "@ fild%z1\t%1 #" [(set_attr "type" "fmov,multi") (set_attr "mode" "SF") - (set_attr "unit" "*,i387") (set_attr "fp_int_src" "true")]) (define_expand "floatsisf2" [(set (match_operand:SF 0 "register_operand" "") (float:SF (match_operand:SI 1 "nonimmediate_operand" "")))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_SSE || TARGET_80387" "") -(define_insn "*floatsisf2_mixed" - [(set (match_operand:SF 0 "register_operand" "=f,?f,x,x") +(define_insn "*floatsisf2_i387" + [(set (match_operand:SF 0 "register_operand" "=f#x,?f#x,x#f,x#f") (float:SF (match_operand:SI 1 "nonimmediate_operand" "m,r,r,mr")))] - "TARGET_MIX_SSE_I387" + "TARGET_80387 && (!TARGET_SSE || TARGET_MIX_SSE_I387)" "@ fild%z1\t%1 # @@ -4481,42 +4504,56 @@ cvtsi2ss\t{%1, %0|%0, %1}" [(set_attr "type" "fmov,multi,sseicvt,sseicvt") (set_attr "mode" "SF") - (set_attr "unit" "*,i387,*,*") (set_attr "athlon_decode" "*,*,vector,double") (set_attr "fp_int_src" "true")]) (define_insn "*floatsisf2_sse" [(set (match_operand:SF 0 "register_operand" "=x,x") (float:SF (match_operand:SI 1 "nonimmediate_operand" "r,mr")))] - "TARGET_SSE_MATH" + "TARGET_SSE" "cvtsi2ss\t{%1, %0|%0, %1}" [(set_attr "type" "sseicvt") (set_attr "mode" "SF") (set_attr "athlon_decode" "vector,double") (set_attr "fp_int_src" "true")]) -(define_insn "*floatsisf2_i387" - [(set (match_operand:SF 0 "register_operand" "=f,f") - (float:SF (match_operand:SI 1 "nonimmediate_operand" "m,?r")))] - "TARGET_80387" +; Avoid possible reformatting penalty on the destination by first +; zeroing it out +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "")))] + "TARGET_80387 && reload_completed && TARGET_SSE_PARTIAL_REGS + && SSE_REG_P (operands[0])" + [(const_int 0)] +{ + rtx dest; + dest = simplify_gen_subreg (V4SFmode, operands[0], SFmode, 0); + emit_insn (gen_sse_clrv4sf (dest, CONST0_RTX (V4SFmode))); + emit_insn (gen_cvtsi2ss (dest, dest, operands[1])); + DONE; +}) + +(define_expand "floatdisf2" + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:DI 1 "nonimmediate_operand" "")))] + "(TARGET_64BIT && TARGET_SSE) || TARGET_80387" + "") + +(define_insn "*floatdisf2_i387_only" + [(set (match_operand:SF 0 "register_operand" "=f,?f") + (float:SF (match_operand:DI 1 "nonimmediate_operand" "m,r")))] + "TARGET_80387 && (!TARGET_SSE || !TARGET_64BIT || TARGET_MIX_SSE_I387)" "@ fild%z1\t%1 #" [(set_attr "type" "fmov,multi") (set_attr "mode" "SF") - (set_attr "unit" "*,i387") (set_attr "fp_int_src" "true")]) -(define_expand "floatdisf2" - [(set (match_operand:SF 0 "register_operand" "") - (float:SF (match_operand:DI 1 "nonimmediate_operand" "")))] - "TARGET_80387 || (TARGET_64BIT && TARGET_SSE_MATH)" - "") - -(define_insn "*floatdisf2_mixed" - [(set (match_operand:SF 0 "register_operand" "=f,?f,x,x") +(define_insn "*floatdisf2_i387" + [(set (match_operand:SF 0 "register_operand" "=f#x,?f#x,x#f,x#f") (float:SF (match_operand:DI 1 "nonimmediate_operand" "m,r,r,mr")))] - "TARGET_64BIT && TARGET_MIX_SSE_I387" + "TARGET_64BIT && TARGET_80387 && (!TARGET_SSE || TARGET_MIX_SSE_I387)" "@ fild%z1\t%1 # @@ -4524,38 +4561,41 @@ cvtsi2ss{q}\t{%1, %0|%0, %1}" [(set_attr "type" "fmov,multi,sseicvt,sseicvt") (set_attr "mode" "SF") - (set_attr "unit" "*,i387,*,*") (set_attr "athlon_decode" "*,*,vector,double") (set_attr "fp_int_src" "true")]) (define_insn "*floatdisf2_sse" [(set (match_operand:SF 0 "register_operand" "=x,x") (float:SF (match_operand:DI 1 "nonimmediate_operand" "r,mr")))] - "TARGET_64BIT && TARGET_SSE_MATH" + "TARGET_64BIT && TARGET_SSE" "cvtsi2ss{q}\t{%1, %0|%0, %1}" [(set_attr "type" "sseicvt") (set_attr "mode" "SF") (set_attr "athlon_decode" "vector,double") (set_attr "fp_int_src" "true")]) -(define_insn "*floatdisf2_i387" - [(set (match_operand:SF 0 "register_operand" "=f,f") - (float:SF (match_operand:DI 1 "nonimmediate_operand" "m,?r")))] - "TARGET_80387" - "@ - fild%z1\t%1 - #" - [(set_attr "type" "fmov,multi") - (set_attr "mode" "SF") - (set_attr "unit" "*,i387") - (set_attr "fp_int_src" "true")]) +; Avoid possible reformatting penalty on the destination by first +; zeroing it out +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:DI 1 "nonimmediate_operand" "")))] + "TARGET_80387 && reload_completed && TARGET_SSE_PARTIAL_REGS + && SSE_REG_P (operands[0])" + [(const_int 0)] +{ + rtx dest; + dest = simplify_gen_subreg (V4SFmode, operands[0], SFmode, 0); + emit_insn (gen_sse_clrv4sf (dest, CONST0_RTX (V4SFmode))); + emit_insn (gen_cvtsi2ssq (dest, dest, operands[1])); + DONE; +}) (define_expand "floathidf2" [(set (match_operand:DF 0 "register_operand" "") (float:DF (match_operand:HI 1 "nonimmediate_operand" "")))] - "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" + "TARGET_SSE2 || TARGET_80387" { - if (TARGET_SSE2 && TARGET_SSE_MATH) + if (TARGET_SSE && TARGET_SSE_MATH) { emit_insn (gen_floatsidf2 (operands[0], convert_to_mode (SImode, operands[1], 0))); @@ -4563,28 +4603,27 @@ } }) -(define_insn "*floathidf2_i387" +(define_insn "*floathidf2_1" [(set (match_operand:DF 0 "register_operand" "=f,f") - (float:DF (match_operand:HI 1 "nonimmediate_operand" "m,?r")))] - "TARGET_80387 && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387)" + (float:DF (match_operand:HI 1 "nonimmediate_operand" "m,r")))] + "TARGET_80387 && (!TARGET_SSE2 || !TARGET_SSE_MATH)" "@ fild%z1\t%1 #" [(set_attr "type" "fmov,multi") (set_attr "mode" "DF") - (set_attr "unit" "*,i387") (set_attr "fp_int_src" "true")]) (define_expand "floatsidf2" [(set (match_operand:DF 0 "register_operand" "") (float:DF (match_operand:SI 1 "nonimmediate_operand" "")))] - "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" + "TARGET_80387 || TARGET_SSE2" "") -(define_insn "*floatsidf2_mixed" - [(set (match_operand:DF 0 "register_operand" "=f,?f,Y,Y") +(define_insn "*floatsidf2_i387" + [(set (match_operand:DF 0 "register_operand" "=f#Y,?f#Y,Y#f,Y#f") (float:DF (match_operand:SI 1 "nonimmediate_operand" "m,r,r,mr")))] - "TARGET_SSE2 && TARGET_MIX_SSE_I387" + "TARGET_80387 && (!TARGET_SSE2 || TARGET_MIX_SSE_I387)" "@ fild%z1\t%1 # @@ -4592,42 +4631,40 @@ cvtsi2sd\t{%1, %0|%0, %1}" [(set_attr "type" "fmov,multi,sseicvt,sseicvt") (set_attr "mode" "DF") - (set_attr "unit" "*,i387,*,*") (set_attr "athlon_decode" "*,*,double,direct") (set_attr "fp_int_src" "true")]) (define_insn "*floatsidf2_sse" [(set (match_operand:DF 0 "register_operand" "=Y,Y") (float:DF (match_operand:SI 1 "nonimmediate_operand" "r,mr")))] - "TARGET_SSE2 && TARGET_SSE_MATH" + "TARGET_SSE2" "cvtsi2sd\t{%1, %0|%0, %1}" [(set_attr "type" "sseicvt") (set_attr "mode" "DF") (set_attr "athlon_decode" "double,direct") (set_attr "fp_int_src" "true")]) -(define_insn "*floatsidf2_i387" - [(set (match_operand:DF 0 "register_operand" "=f,f") - (float:DF (match_operand:SI 1 "nonimmediate_operand" "m,?r")))] - "TARGET_80387" +(define_expand "floatdidf2" + [(set (match_operand:DF 0 "register_operand" "") + (float:DF (match_operand:DI 1 "nonimmediate_operand" "")))] + "(TARGET_64BIT && TARGET_SSE2) || TARGET_80387" + "") + +(define_insn "*floatdidf2_i387_only" + [(set (match_operand:DF 0 "register_operand" "=f,?f") + (float:DF (match_operand:DI 1 "nonimmediate_operand" "m,r")))] + "TARGET_80387 && (!TARGET_SSE2 || !TARGET_64BIT)" "@ fild%z1\t%1 #" [(set_attr "type" "fmov,multi") (set_attr "mode" "DF") - (set_attr "unit" "*,i387") (set_attr "fp_int_src" "true")]) -(define_expand "floatdidf2" - [(set (match_operand:DF 0 "register_operand" "") - (float:DF (match_operand:DI 1 "nonimmediate_operand" "")))] - "TARGET_80387 || (TARGET_64BIT && TARGET_SSE2 && TARGET_SSE_MATH)" - "") - -(define_insn "*floatdidf2_mixed" - [(set (match_operand:DF 0 "register_operand" "=f,?f,Y,Y") +(define_insn "*floatdidf2_i387" + [(set (match_operand:DF 0 "register_operand" "=f#Y,?f#Y,Y#f,Y#f") (float:DF (match_operand:DI 1 "nonimmediate_operand" "m,r,r,mr")))] - "TARGET_64BIT && TARGET_SSE2 && TARGET_MIX_SSE_I387" + "TARGET_64BIT && TARGET_80387 && (!TARGET_SSE2 || TARGET_MIX_SSE_I387)" "@ fild%z1\t%1 # @@ -4635,75 +4672,57 @@ cvtsi2sd{q}\t{%1, %0|%0, %1}" [(set_attr "type" "fmov,multi,sseicvt,sseicvt") (set_attr "mode" "DF") - (set_attr "unit" "*,i387,*,*") (set_attr "athlon_decode" "*,*,double,direct") (set_attr "fp_int_src" "true")]) (define_insn "*floatdidf2_sse" [(set (match_operand:DF 0 "register_operand" "=Y,Y") (float:DF (match_operand:DI 1 "nonimmediate_operand" "r,mr")))] - "TARGET_64BIT && TARGET_SSE2 && TARGET_SSE_MATH" + "TARGET_SSE2" "cvtsi2sd{q}\t{%1, %0|%0, %1}" [(set_attr "type" "sseicvt") (set_attr "mode" "DF") (set_attr "athlon_decode" "double,direct") (set_attr "fp_int_src" "true")]) -(define_insn "*floatdidf2_i387" - [(set (match_operand:DF 0 "register_operand" "=f,f") - (float:DF (match_operand:DI 1 "nonimmediate_operand" "m,?r")))] - "TARGET_80387" - "@ - fild%z1\t%1 - #" - [(set_attr "type" "fmov,multi") - (set_attr "mode" "DF") - (set_attr "unit" "*,i387") - (set_attr "fp_int_src" "true")]) - (define_insn "floathixf2" [(set (match_operand:XF 0 "register_operand" "=f,f") - (float:XF (match_operand:HI 1 "nonimmediate_operand" "m,?r")))] + (float:XF (match_operand:HI 1 "nonimmediate_operand" "m,r")))] "TARGET_80387" "@ fild%z1\t%1 #" [(set_attr "type" "fmov,multi") (set_attr "mode" "XF") - (set_attr "unit" "*,i387") (set_attr "fp_int_src" "true")]) (define_insn "floatsixf2" [(set (match_operand:XF 0 "register_operand" "=f,f") - (float:XF (match_operand:SI 1 "nonimmediate_operand" "m,?r")))] + (float:XF (match_operand:SI 1 "nonimmediate_operand" "m,r")))] "TARGET_80387" "@ fild%z1\t%1 #" [(set_attr "type" "fmov,multi") (set_attr "mode" "XF") - (set_attr "unit" "*,i387") (set_attr "fp_int_src" "true")]) (define_insn "floatdixf2" [(set (match_operand:XF 0 "register_operand" "=f,f") - (float:XF (match_operand:DI 1 "nonimmediate_operand" "m,?r")))] + (float:XF (match_operand:DI 1 "nonimmediate_operand" "m,r")))] "TARGET_80387" "@ fild%z1\t%1 #" [(set_attr "type" "fmov,multi") (set_attr "mode" "XF") - (set_attr "unit" "*,i387") (set_attr "fp_int_src" "true")]) ;; %%% Kill these when reload knows how to do it. (define_split [(set (match_operand 0 "fp_register_operand" "") (float (match_operand 1 "register_operand" "")))] - "reload_completed - && TARGET_80387 - && FLOAT_MODE_P (GET_MODE (operands[0]))" + "reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))" [(const_int 0)] { operands[2] = ix86_force_to_memory (GET_MODE (operands[1]), operands[1]); @@ -4716,61 +4735,187 @@ (define_expand "floatunssisf2" [(use (match_operand:SF 0 "register_operand" "")) (use (match_operand:SI 1 "register_operand" ""))] - "!TARGET_64BIT && TARGET_SSE_MATH" + "TARGET_SSE && TARGET_SSE_MATH && !TARGET_64BIT" "x86_emit_floatuns (operands); DONE;") (define_expand "floatunsdisf2" [(use (match_operand:SF 0 "register_operand" "")) (use (match_operand:DI 1 "register_operand" ""))] - "TARGET_64BIT && TARGET_SSE_MATH" + "TARGET_SSE && TARGET_SSE_MATH && TARGET_64BIT" "x86_emit_floatuns (operands); DONE;") (define_expand "floatunsdidf2" [(use (match_operand:DF 0 "register_operand" "")) (use (match_operand:DI 1 "register_operand" ""))] - "TARGET_64BIT && TARGET_SSE2 && TARGET_SSE_MATH" + "TARGET_SSE2 && TARGET_SSE_MATH && TARGET_64BIT" "x86_emit_floatuns (operands); DONE;") ;; SSE extract/set expanders - -;; Add instructions +(define_expand "vec_setv2df" + [(match_operand:V2DF 0 "register_operand" "") + (match_operand:DF 1 "register_operand" "") + (match_operand 2 "const_int_operand" "")] + "TARGET_SSE2" +{ + switch (INTVAL (operands[2])) + { + case 0: + emit_insn (gen_sse2_movsd (operands[0], operands[0], + simplify_gen_subreg (V2DFmode, operands[1], + DFmode, 0))); + break; + case 1: + { + rtx op1 = simplify_gen_subreg (V2DFmode, operands[1], DFmode, 0); + + emit_insn (gen_sse2_unpcklpd (operands[0], operands[0], op1)); + } + break; + default: + abort (); + } + DONE; +}) -;; %%% splits for addditi3 +(define_expand "vec_extractv2df" + [(match_operand:DF 0 "register_operand" "") + (match_operand:V2DF 1 "register_operand" "") + (match_operand 2 "const_int_operand" "")] + "TARGET_SSE2" +{ + switch (INTVAL (operands[2])) + { + case 0: + emit_move_insn (operands[0], gen_lowpart (DFmode, operands[1])); + break; + case 1: + { + rtx dest = simplify_gen_subreg (V2DFmode, operands[0], DFmode, 0); -(define_expand "addti3" - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (plus:TI (match_operand:TI 1 "nonimmediate_operand" "") - (match_operand:TI 2 "x86_64_general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "ix86_expand_binary_operator (PLUS, TImode, operands); DONE;") - -(define_insn "*addti3_1" - [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o") - (plus:TI (match_operand:TI 1 "nonimmediate_operand" "%0,0") - (match_operand:TI 2 "general_operand" "roiF,riF"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (PLUS, TImode, operands)" - "#") + emit_insn (gen_sse2_unpckhpd (dest, operands[1], operands[1])); + } + break; + default: + abort (); + } + DONE; +}) -(define_split - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (plus:TI (match_operand:TI 1 "nonimmediate_operand" "") - (match_operand:TI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(parallel [(set (reg:CC FLAGS_REG) (unspec:CC [(match_dup 1) (match_dup 2)] - UNSPEC_ADD_CARRY)) - (set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))]) - (parallel [(set (match_dup 3) - (plus:DI (plus:DI (ltu:DI (reg:CC FLAGS_REG) (const_int 0)) - (match_dup 4)) - (match_dup 5))) - (clobber (reg:CC FLAGS_REG))])] - "split_ti (operands+0, 1, operands+0, operands+3); - split_ti (operands+1, 1, operands+1, operands+4); - split_ti (operands+2, 1, operands+2, operands+5);") +(define_expand "vec_initv2df" + [(match_operand:V2DF 0 "register_operand" "") + (match_operand 1 "" "")] + "TARGET_SSE2" +{ + ix86_expand_vector_init (operands[0], operands[1]); + DONE; +}) + +(define_expand "vec_setv4sf" + [(match_operand:V4SF 0 "register_operand" "") + (match_operand:SF 1 "register_operand" "") + (match_operand 2 "const_int_operand" "")] + "TARGET_SSE" +{ + switch (INTVAL (operands[2])) + { + case 0: + emit_insn (gen_sse_movss (operands[0], operands[0], + simplify_gen_subreg (V4SFmode, operands[1], + SFmode, 0))); + break; + case 1: + { + rtx op1 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0); + rtx tmp = gen_reg_rtx (V4SFmode); + + emit_move_insn (tmp, operands[0]); + emit_insn (gen_sse_unpcklps (operands[0], operands[0], operands[0])); + emit_insn (gen_sse_movss (operands[0], operands[0], op1)); + emit_insn (gen_sse_shufps (operands[0], operands[0], tmp, + GEN_INT (1 + (0<<2) + (2<<4) + (3<<6)))); + } + case 2: + { + rtx op1 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0); + rtx tmp = gen_reg_rtx (V4SFmode); + + emit_move_insn (tmp, operands[0]); + emit_insn (gen_sse_movss (tmp, tmp, op1)); + emit_insn (gen_sse_shufps (operands[0], operands[0], tmp, + GEN_INT (0 + (1<<2) + (0<<4) + (3<<6)))); + } + break; + case 3: + { + rtx op1 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0); + rtx tmp = gen_reg_rtx (V4SFmode); + + emit_move_insn (tmp, operands[0]); + emit_insn (gen_sse_movss (tmp, tmp, op1)); + emit_insn (gen_sse_shufps (operands[0], operands[0], tmp, + GEN_INT (0 + (1<<2) + (2<<4) + (0<<6)))); + } + break; + default: + abort (); + } + DONE; +}) + +(define_expand "vec_extractv4sf" + [(match_operand:SF 0 "register_operand" "") + (match_operand:V4SF 1 "register_operand" "") + (match_operand 2 "const_int_operand" "")] + "TARGET_SSE" +{ + switch (INTVAL (operands[2])) + { + case 0: + emit_move_insn (operands[0], gen_lowpart (SFmode, operands[1])); + break; + case 1: + { + rtx op0 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0); + rtx tmp = gen_reg_rtx (V4SFmode); + + emit_move_insn (tmp, operands[1]); + emit_insn (gen_sse_shufps (op0, tmp, tmp, + GEN_INT (1))); + } + case 2: + { + rtx op0 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0); + rtx tmp = gen_reg_rtx (V4SFmode); + + emit_move_insn (tmp, operands[1]); + emit_insn (gen_sse_unpckhps (op0, tmp, tmp)); + } + case 3: + { + rtx op0 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0); + rtx tmp = gen_reg_rtx (V4SFmode); + + emit_move_insn (tmp, operands[1]); + emit_insn (gen_sse_shufps (op0, tmp, tmp, + GEN_INT (3))); + } + default: + abort (); + } + DONE; +}) + +(define_expand "vec_initv4sf" + [(match_operand:V4SF 0 "register_operand" "") + (match_operand 1 "" "")] + "TARGET_SSE" +{ + ix86_expand_vector_init (operands[0], operands[1]); + DONE; +}) + +;; Add instructions ;; %%% splits for addsidi3 ; [(set (match_operand:DI 0 "nonimmediate_operand" "") @@ -4781,7 +4926,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "") (plus:DI (match_operand:DI 1 "nonimmediate_operand" "") (match_operand:DI 2 "x86_64_general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "ix86_expand_binary_operator (PLUS, DImode, operands); DONE;") @@ -4789,7 +4934,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") (match_operand:DI 2 "general_operand" "roiF,riF"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && ix86_binary_operator_ok (PLUS, DImode, operands)" "#") @@ -4797,16 +4942,16 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "") (plus:DI (match_operand:DI 1 "nonimmediate_operand" "") (match_operand:DI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && reload_completed" - [(parallel [(set (reg:CC FLAGS_REG) (unspec:CC [(match_dup 1) (match_dup 2)] + [(parallel [(set (reg:CC 17) (unspec:CC [(match_dup 1) (match_dup 2)] UNSPEC_ADD_CARRY)) (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]) (parallel [(set (match_dup 3) - (plus:SI (plus:SI (ltu:SI (reg:CC FLAGS_REG) (const_int 0)) + (plus:SI (plus:SI (ltu:SI (reg:CC 17) (const_int 0)) (match_dup 4)) (match_dup 5))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "split_di (operands+0, 1, operands+0, operands+3); split_di (operands+1, 1, operands+1, operands+4); split_di (operands+2, 1, operands+2, operands+5);") @@ -4816,15 +4961,16 @@ (plus:DI (plus:DI (match_operand:DI 3 "ix86_carry_flag_operator" "") (match_operand:DI 1 "nonimmediate_operand" "%0,0")) (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (PLUS, DImode, operands)" "adc{q}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "pent_pair" "pu") - (set_attr "mode" "DI")]) + (set_attr "mode" "DI") + (set_attr "ppro_uops" "few")]) (define_insn "*adddi3_cc_rex64" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (unspec:CC [(match_operand:DI 1 "nonimmediate_operand" "%0,0") (match_operand:DI 2 "x86_64_general_operand" "re,rm")] UNSPEC_ADD_CARRY)) @@ -4840,36 +4986,39 @@ (plus:QI (plus:QI (match_operand:QI 3 "ix86_carry_flag_operator" "") (match_operand:QI 1 "nonimmediate_operand" "%0,0")) (match_operand:QI 2 "general_operand" "qi,qm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (PLUS, QImode, operands)" "adc{b}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "pent_pair" "pu") - (set_attr "mode" "QI")]) + (set_attr "mode" "QI") + (set_attr "ppro_uops" "few")]) (define_insn "addhi3_carry" [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") (plus:HI (plus:HI (match_operand:HI 3 "ix86_carry_flag_operator" "") (match_operand:HI 1 "nonimmediate_operand" "%0,0")) (match_operand:HI 2 "general_operand" "ri,rm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (PLUS, HImode, operands)" "adc{w}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "pent_pair" "pu") - (set_attr "mode" "HI")]) + (set_attr "mode" "HI") + (set_attr "ppro_uops" "few")]) (define_insn "addsi3_carry" [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") (plus:SI (plus:SI (match_operand:SI 3 "ix86_carry_flag_operator" "") (match_operand:SI 1 "nonimmediate_operand" "%0,0")) (match_operand:SI 2 "general_operand" "ri,rm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (PLUS, SImode, operands)" "adc{l}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "pent_pair" "pu") - (set_attr "mode" "SI")]) + (set_attr "mode" "SI") + (set_attr "ppro_uops" "few")]) (define_insn "*addsi3_carry_zext" [(set (match_operand:DI 0 "register_operand" "=r") @@ -4877,15 +5026,16 @@ (plus:SI (plus:SI (match_operand:SI 3 "ix86_carry_flag_operator" "") (match_operand:SI 1 "nonimmediate_operand" "%0")) (match_operand:SI 2 "general_operand" "rim")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (PLUS, SImode, operands)" "adc{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") (set_attr "pent_pair" "pu") - (set_attr "mode" "SI")]) + (set_attr "mode" "SI") + (set_attr "ppro_uops" "few")]) (define_insn "*addsi3_cc" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (unspec:CC [(match_operand:SI 1 "nonimmediate_operand" "%0,0") (match_operand:SI 2 "general_operand" "ri,rm")] UNSPEC_ADD_CARRY)) @@ -4897,7 +5047,7 @@ (set_attr "mode" "SI")]) (define_insn "addqi3_cc" - [(set (reg:CC FLAGS_REG) + [(set (reg:CC 17) (unspec:CC [(match_operand:QI 1 "nonimmediate_operand" "%0,0") (match_operand:QI 2 "general_operand" "qi,qm")] UNSPEC_ADD_CARRY)) @@ -4912,7 +5062,7 @@ [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") (plus:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:SI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "ix86_expand_binary_operator (PLUS, SImode, operands); DONE;") @@ -4954,7 +5104,7 @@ (define_insn_and_split "*lea_general_1" [(set (match_operand 0 "register_operand" "=r") - (plus (plus (match_operand 1 "index_register_operand" "l") + (plus (plus (match_operand 1 "index_register_operand" "r") (match_operand 2 "register_operand" "r")) (match_operand 3 "immediate_operand" "i")))] "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode @@ -4986,7 +5136,7 @@ (define_insn_and_split "*lea_general_1_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI - (plus:SI (plus:SI (match_operand:SI 1 "index_register_operand" "l") + (plus:SI (plus:SI (match_operand:SI 1 "index_register_operand" "r") (match_operand:SI 2 "register_operand" "r")) (match_operand:SI 3 "immediate_operand" "i"))))] "TARGET_64BIT" @@ -5006,7 +5156,7 @@ (define_insn_and_split "*lea_general_2" [(set (match_operand 0 "register_operand" "=r") - (plus (mult (match_operand 1 "index_register_operand" "l") + (plus (mult (match_operand 1 "index_register_operand" "r") (match_operand 2 "const248_operand" "i")) (match_operand 3 "nonmemory_operand" "ri")))] "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode @@ -5036,7 +5186,7 @@ (define_insn_and_split "*lea_general_2_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI - (plus:SI (mult:SI (match_operand:SI 1 "index_register_operand" "l") + (plus:SI (mult:SI (match_operand:SI 1 "index_register_operand" "r") (match_operand:SI 2 "const248_operand" "n")) (match_operand:SI 3 "nonmemory_operand" "ri"))))] "TARGET_64BIT" @@ -5055,7 +5205,7 @@ (define_insn_and_split "*lea_general_3" [(set (match_operand 0 "register_operand" "=r") - (plus (plus (mult (match_operand 1 "index_register_operand" "l") + (plus (plus (mult (match_operand 1 "index_register_operand" "r") (match_operand 2 "const248_operand" "i")) (match_operand 3 "register_operand" "r")) (match_operand 4 "immediate_operand" "i")))] @@ -5089,9 +5239,8 @@ (define_insn_and_split "*lea_general_3_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI - (plus:SI (plus:SI (mult:SI - (match_operand:SI 1 "index_register_operand" "l") - (match_operand:SI 2 "const248_operand" "n")) + (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "index_register_operand" "r") + (match_operand:SI 2 "const248_operand" "n")) (match_operand:SI 3 "register_operand" "r")) (match_operand:SI 4 "immediate_operand" "i"))))] "TARGET_64BIT" @@ -5113,8 +5262,8 @@ (define_insn "*adddi_1_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=r,rm,r") (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,r") - (match_operand:DI 2 "x86_64_general_operand" "rme,re,le"))) - (clobber (reg:CC FLAGS_REG))] + (match_operand:DI 2 "x86_64_general_operand" "rme,re,re"))) + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (PLUS, DImode, operands)" { switch (get_attr_type (insn)) @@ -5124,17 +5273,18 @@ return "lea{q}\t{%a2, %0|%0, %a2}"; case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); if (operands[2] == const1_rtx) return "inc{q}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{q}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{q}\t%0"; - } + abort (); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ @@ -5169,7 +5319,7 @@ [(set (match_operand:DI 0 "register_operand" "") (plus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "x86_64_nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && reload_completed && true_regnum (operands[0]) != true_regnum (operands[1])" [(set (match_dup 0) @@ -5178,7 +5328,7 @@ "") (define_insn "*adddi_2_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") (match_operand:DI 2 "x86_64_general_operand" "rme,re")) @@ -5194,17 +5344,18 @@ switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); if (operands[2] == const1_rtx) return "inc{q}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{q}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{q}\t%0"; - } + abort (); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* ???? We ought to handle there the 32bit case too - do we need new constraint? */ /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -5229,7 +5380,7 @@ (set_attr "mode" "DI")]) (define_insn "*adddi_3_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (neg:DI (match_operand:DI 2 "x86_64_general_operand" "rme")) (match_operand:DI 1 "x86_64_general_operand" "%0"))) (clobber (match_scratch:DI 0 "=r"))] @@ -5243,17 +5394,18 @@ switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); if (operands[2] == const1_rtx) return "inc{q}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{q}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{q}\t%0"; - } + abort (); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* ???? We ought to handle there the 32bit case too - do we need new constraint? */ /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -5286,7 +5438,7 @@ ; Also carry flag is reversed compared to cmp, so this conversion is valid ; only for comparisons not depending on it. (define_insn "*adddi_4_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:DI 2 "x86_64_immediate_operand" "e"))) (clobber (match_scratch:DI 0 "=rm"))] @@ -5298,14 +5450,14 @@ case TYPE_INCDEC: if (operands[2] == constm1_rtx) return "inc{q}\t%0"; + else if (operands[2] == const1_rtx) + return "dec{q}\t%0"; else - { - gcc_assert (operands[2] == const1_rtx); - return "dec{q}\t%0"; - } + abort(); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if ((INTVAL (operands[2]) == -128 @@ -5325,7 +5477,7 @@ (set_attr "mode" "DI")]) (define_insn "*adddi_5_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") (match_operand:DI 2 "x86_64_general_operand" "rme")) @@ -5341,17 +5493,18 @@ switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); if (operands[2] == const1_rtx) return "inc{q}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{q}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{q}\t%0"; - } + abort(); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (GET_CODE (operands[2]) == CONST_INT @@ -5377,8 +5530,8 @@ (define_insn "*addsi_1" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r") (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,r") - (match_operand:SI 2 "general_operand" "rmni,rni,lni"))) - (clobber (reg:CC FLAGS_REG))] + (match_operand:SI 2 "general_operand" "rmni,rni,rni"))) + (clobber (reg:CC 17))] "ix86_binary_operator_ok (PLUS, SImode, operands)" { switch (get_attr_type (insn)) @@ -5388,17 +5541,18 @@ return "lea{l}\t{%a2, %0|%0, %a2}"; case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); if (operands[2] == const1_rtx) return "inc{l}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%0"; - } + abort(); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ @@ -5431,7 +5585,7 @@ [(set (match_operand 0 "register_operand" "") (plus (match_operand 1 "register_operand" "") (match_operand 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && true_regnum (operands[0]) != true_regnum (operands[1])" [(const_int 0)] @@ -5461,8 +5615,8 @@ [(set (match_operand:DI 0 "register_operand" "=r,r") (zero_extend:DI (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,r") - (match_operand:SI 2 "general_operand" "rmni,lni")))) - (clobber (reg:CC FLAGS_REG))] + (match_operand:SI 2 "general_operand" "rmni,rni")))) + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (PLUS, SImode, operands)" { switch (get_attr_type (insn)) @@ -5474,11 +5628,10 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{l}\t%k0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%k0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%k0"; - } + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -5513,7 +5666,7 @@ (zero_extend:DI (plus:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "nonmemory_operand" "")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && reload_completed && true_regnum (operands[0]) != true_regnum (operands[1])" [(set (match_dup 0) @@ -5524,7 +5677,7 @@ }) (define_insn "*addsi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") (match_operand:SI 2 "general_operand" "rmni,rni")) @@ -5540,17 +5693,18 @@ switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); if (operands[2] == const1_rtx) return "inc{l}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%0"; - } + abort(); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (GET_CODE (operands[2]) == CONST_INT @@ -5572,7 +5726,7 @@ ;; See comment for addsi_1_zext why we do use nonimmediate_operand (define_insn "*addsi_2_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand:SI 2 "general_operand" "rmni")) @@ -5590,11 +5744,10 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{l}\t%k0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%k0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%k0"; - } + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -5617,7 +5770,7 @@ (set_attr "mode" "SI")]) (define_insn "*addsi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (neg:SI (match_operand:SI 2 "general_operand" "rmni")) (match_operand:SI 1 "nonimmediate_operand" "%0"))) (clobber (match_scratch:SI 0 "=r"))] @@ -5630,17 +5783,18 @@ switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); if (operands[2] == const1_rtx) return "inc{l}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%0"; - } + abort(); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (GET_CODE (operands[2]) == CONST_INT @@ -5662,7 +5816,7 @@ ;; See comment for addsi_1_zext why we do use nonimmediate_operand (define_insn "*addsi_3_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (neg:SI (match_operand:SI 2 "general_operand" "rmni")) (match_operand:SI 1 "nonimmediate_operand" "%0"))) (set (match_operand:DI 0 "register_operand" "=r") @@ -5678,11 +5832,10 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{l}\t%k0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%k0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%k0"; - } + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -5713,7 +5866,7 @@ ; Also carry flag is reversed compared to cmp, so this conversion is valid ; only for comparisons not depending on it. (define_insn "*addsi_4" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:SI 2 "const_int_operand" "n"))) (clobber (match_scratch:SI 0 "=rm"))] @@ -5725,14 +5878,14 @@ case TYPE_INCDEC: if (operands[2] == constm1_rtx) return "inc{l}\t%0"; + else if (operands[2] == const1_rtx) + return "dec{l}\t%0"; else - { - gcc_assert (operands[2] == const1_rtx); - return "dec{l}\t%0"; - } + abort(); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if ((INTVAL (operands[2]) == -128 @@ -5750,7 +5903,7 @@ (set_attr "mode" "SI")]) (define_insn "*addsi_5" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand:SI 2 "general_operand" "rmni")) @@ -5765,17 +5918,18 @@ switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); if (operands[2] == const1_rtx) return "inc{l}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%0"; - } + abort(); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (GET_CODE (operands[2]) == CONST_INT @@ -5799,7 +5953,7 @@ [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "") (plus:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_HIMODE_MATH" "ix86_expand_binary_operator (PLUS, HImode, operands); DONE;") @@ -5810,8 +5964,8 @@ (define_insn "*addhi_1_lea" [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r") (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,r") - (match_operand:HI 2 "general_operand" "ri,rm,lni"))) - (clobber (reg:CC FLAGS_REG))] + (match_operand:HI 2 "general_operand" "ri,rm,rni"))) + (clobber (reg:CC 17))] "!TARGET_PARTIAL_REG_STALL && ix86_binary_operator_ok (PLUS, HImode, operands)" { @@ -5822,11 +5976,9 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{w}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; - } + else if (operands[2] == constm1_rtx) + return "dec{w}\t%0"; + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -5854,7 +6006,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") (match_operand:HI 2 "general_operand" "ri,rm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_PARTIAL_REG_STALL && ix86_binary_operator_ok (PLUS, HImode, operands)" { @@ -5863,11 +6015,9 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{w}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; - } + else if (operands[2] == constm1_rtx) + return "dec{w}\t%0"; + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -5890,7 +6040,7 @@ (set_attr "mode" "HI")]) (define_insn "*addhi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") (match_operand:HI 2 "general_operand" "rmni,rni")) @@ -5905,11 +6055,9 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{w}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; - } + else if (operands[2] == constm1_rtx) + return "dec{w}\t%0"; + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -5932,7 +6080,7 @@ (set_attr "mode" "HI")]) (define_insn "*addhi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (neg:HI (match_operand:HI 2 "general_operand" "rmni")) (match_operand:HI 1 "nonimmediate_operand" "%0"))) (clobber (match_scratch:HI 0 "=r"))] @@ -5944,11 +6092,9 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{w}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; - } + else if (operands[2] == constm1_rtx) + return "dec{w}\t%0"; + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -5970,9 +6116,9 @@ (const_string "alu"))) (set_attr "mode" "HI")]) -; See comments above addsi_4 for details. +; See comments above addsi_3_imm for details. (define_insn "*addhi_4" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:HI 2 "const_int_operand" "n"))) (clobber (match_scratch:HI 0 "=rm"))] @@ -5984,14 +6130,14 @@ case TYPE_INCDEC: if (operands[2] == constm1_rtx) return "inc{w}\t%0"; + else if (operands[2] == const1_rtx) + return "dec{w}\t%0"; else - { - gcc_assert (operands[2] == const1_rtx); - return "dec{w}\t%0"; - } + abort(); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if ((INTVAL (operands[2]) == -128 @@ -6010,7 +6156,7 @@ (define_insn "*addhi_5" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0") (match_operand:HI 2 "general_operand" "rmni")) @@ -6024,11 +6170,9 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{w}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; - } + else if (operands[2] == constm1_rtx) + return "dec{w}\t%0"; + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -6054,7 +6198,7 @@ [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "") (plus:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_QIMODE_MATH" "ix86_expand_binary_operator (PLUS, QImode, operands); DONE;") @@ -6062,8 +6206,8 @@ (define_insn "*addqi_1_lea" [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r,r") (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0,r") - (match_operand:QI 2 "general_operand" "qn,qmn,rn,ln"))) - (clobber (reg:CC FLAGS_REG))] + (match_operand:QI 2 "general_operand" "qn,qmn,rn,rn"))) + (clobber (reg:CC 17))] "!TARGET_PARTIAL_REG_STALL && ix86_binary_operator_ok (PLUS, QImode, operands)" { @@ -6075,11 +6219,9 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return widen ? "inc{l}\t%k0" : "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx); - return widen ? "dec{l}\t%k0" : "dec{b}\t%0"; - } + else if (operands[2] == constm1_rtx) + return widen ? "dec{l}\t%k0" : "dec{b}\t%0"; + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -6113,7 +6255,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r") (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") (match_operand:QI 2 "general_operand" "qn,qmn,rn"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_PARTIAL_REG_STALL && ix86_binary_operator_ok (PLUS, QImode, operands)" { @@ -6123,11 +6265,9 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return widen ? "inc{l}\t%k0" : "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx); - return widen ? "dec{l}\t%k0" : "dec{b}\t%0"; - } + else if (operands[2] == constm1_rtx) + return widen ? "dec{l}\t%k0" : "dec{b}\t%0"; + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. @@ -6159,7 +6299,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) (plus:QI (match_dup 0) (match_operand:QI 1 "general_operand" "qn,qnm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" { @@ -6168,11 +6308,9 @@ case TYPE_INCDEC: if (operands[1] == const1_rtx) return "inc{b}\t%0"; - else - { - gcc_assert (operands[1] == constm1_rtx); - return "dec{b}\t%0"; - } + else if (operands[1] == constm1_rtx) + return "dec{b}\t%0"; + abort(); default: /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. */ @@ -6196,7 +6334,7 @@ (set_attr "mode" "QI")]) (define_insn "*addqi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") (match_operand:QI 2 "general_operand" "qmni,qni")) @@ -6211,13 +6349,11 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%0"; - } + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "dec{b}\t%0"; + abort(); default: /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'. */ @@ -6237,7 +6373,7 @@ (set_attr "mode" "QI")]) (define_insn "*addqi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (neg:QI (match_operand:QI 2 "general_operand" "qmni")) (match_operand:QI 1 "nonimmediate_operand" "%0"))) (clobber (match_scratch:QI 0 "=q"))] @@ -6249,13 +6385,11 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%0"; - } + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "dec{b}\t%0"; + abort(); default: /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'. */ @@ -6274,9 +6408,9 @@ (const_string "alu"))) (set_attr "mode" "QI")]) -; See comments above addsi_4 for details. +; See comments above addsi_3_imm for details. (define_insn "*addqi_4" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const_int_operand" "n"))) (clobber (match_scratch:QI 0 "=qm"))] @@ -6290,14 +6424,14 @@ || (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 255)) return "inc{b}\t%0"; + else if (operands[2] == const1_rtx) + return "dec{b}\t%0"; else - { - gcc_assert (operands[2] == const1_rtx); - return "dec{b}\t%0"; - } + abort(); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); if (INTVAL (operands[2]) < 0) { operands[2] = GEN_INT (-INTVAL (operands[2])); @@ -6314,7 +6448,7 @@ (define_insn "*addqi_5" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0") (match_operand:QI 2 "general_operand" "qmni")) @@ -6328,13 +6462,11 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%0"; - } + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "dec{b}\t%0"; + abort(); default: /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'. */ @@ -6364,7 +6496,7 @@ (const_int 8) (const_int 8)) (match_operand:QI 2 "general_operand" "Qmn"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT" { switch (get_attr_type (insn)) @@ -6372,13 +6504,11 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{b}\t%h0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%h0"; - } + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "dec{b}\t%h0"; + abort(); default: return "add{b}\t{%2, %h0|%h0, %2}"; @@ -6400,7 +6530,7 @@ (const_int 8) (const_int 8)) (match_operand:QI 2 "nonmemory_operand" "Qn"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" { switch (get_attr_type (insn)) @@ -6408,13 +6538,11 @@ case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{b}\t%h0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%h0"; - } + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "dec{b}\t%h0"; + abort(); default: return "add{b}\t{%2, %h0|%h0, %2}"; @@ -6439,7 +6567,7 @@ (match_operand 2 "ext_register_operand" "Q") (const_int 8) (const_int 8)))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "add{b}\t{%h2, %h0|%h0, %h2}" [(set_attr "type" "alu") @@ -6470,48 +6598,13 @@ ;; Subtract instructions -;; %%% splits for subditi3 - -(define_expand "subti3" - [(parallel [(set (match_operand:TI 0 "nonimmediate_operand" "") - (minus:TI (match_operand:TI 1 "nonimmediate_operand" "") - (match_operand:TI 2 "x86_64_general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" - "ix86_expand_binary_operator (MINUS, TImode, operands); DONE;") - -(define_insn "*subti3_1" - [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o") - (minus:TI (match_operand:TI 1 "nonimmediate_operand" "0,0") - (match_operand:TI 2 "general_operand" "roiF,riF"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (MINUS, TImode, operands)" - "#") - -(define_split - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (minus:TI (match_operand:TI 1 "nonimmediate_operand" "") - (match_operand:TI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(parallel [(set (reg:CC FLAGS_REG) (compare:CC (match_dup 1) (match_dup 2))) - (set (match_dup 0) (minus:DI (match_dup 1) (match_dup 2)))]) - (parallel [(set (match_dup 3) - (minus:DI (match_dup 4) - (plus:DI (ltu:DI (reg:CC FLAGS_REG) (const_int 0)) - (match_dup 5)))) - (clobber (reg:CC FLAGS_REG))])] - "split_ti (operands+0, 1, operands+0, operands+3); - split_ti (operands+1, 1, operands+1, operands+4); - split_ti (operands+2, 1, operands+2, operands+5);") - ;; %%% splits for subsidi3 (define_expand "subdi3" [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") (minus:DI (match_operand:DI 1 "nonimmediate_operand" "") (match_operand:DI 2 "x86_64_general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "ix86_expand_binary_operator (MINUS, DImode, operands); DONE;") @@ -6519,7 +6612,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") (match_operand:DI 2 "general_operand" "roiF,riF"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && ix86_binary_operator_ok (MINUS, DImode, operands)" "#") @@ -6527,15 +6620,15 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "") (minus:DI (match_operand:DI 1 "nonimmediate_operand" "") (match_operand:DI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && reload_completed" - [(parallel [(set (reg:CC FLAGS_REG) (compare:CC (match_dup 1) (match_dup 2))) + [(parallel [(set (reg:CC 17) (compare:CC (match_dup 1) (match_dup 2))) (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))]) (parallel [(set (match_dup 3) (minus:SI (match_dup 4) - (plus:SI (ltu:SI (reg:CC FLAGS_REG) (const_int 0)) + (plus:SI (ltu:SI (reg:CC 17) (const_int 0)) (match_dup 5)))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "split_di (operands+0, 1, operands+0, operands+3); split_di (operands+1, 1, operands+1, operands+4); split_di (operands+2, 1, operands+2, operands+5);") @@ -6545,25 +6638,26 @@ (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") (plus:DI (match_operand:DI 3 "ix86_carry_flag_operator" "") (match_operand:DI 2 "x86_64_general_operand" "re,rm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (MINUS, DImode, operands)" "sbb{q}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "pent_pair" "pu") + (set_attr "ppro_uops" "few") (set_attr "mode" "DI")]) (define_insn "*subdi_1_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (MINUS, DImode, operands)" "sub{q}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "mode" "DI")]) (define_insn "*subdi_2_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") (match_operand:DI 2 "x86_64_general_operand" "re,rm")) @@ -6577,7 +6671,7 @@ (set_attr "mode" "DI")]) (define_insn "*subdi_3_rex63" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:DI 1 "nonimmediate_operand" "0,0") (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) (set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") @@ -6593,11 +6687,12 @@ (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") (plus:QI (match_operand:QI 3 "ix86_carry_flag_operator" "") (match_operand:QI 2 "general_operand" "qi,qm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (MINUS, QImode, operands)" "sbb{b}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "pent_pair" "pu") + (set_attr "ppro_uops" "few") (set_attr "mode" "QI")]) (define_insn "subhi3_carry" @@ -6605,11 +6700,12 @@ (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") (plus:HI (match_operand:HI 3 "ix86_carry_flag_operator" "") (match_operand:HI 2 "general_operand" "ri,rm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (MINUS, HImode, operands)" "sbb{w}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "pent_pair" "pu") + (set_attr "ppro_uops" "few") (set_attr "mode" "HI")]) (define_insn "subsi3_carry" @@ -6617,11 +6713,12 @@ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") (plus:SI (match_operand:SI 3 "ix86_carry_flag_operator" "") (match_operand:SI 2 "general_operand" "ri,rm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (MINUS, SImode, operands)" "sbb{l}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "pent_pair" "pu") + (set_attr "ppro_uops" "few") (set_attr "mode" "SI")]) (define_insn "subsi3_carry_zext" @@ -6630,18 +6727,19 @@ (minus:SI (match_operand:SI 1 "register_operand" "0,0") (plus:SI (match_operand:SI 3 "ix86_carry_flag_operator" "") (match_operand:SI 2 "general_operand" "ri,rm"))))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (MINUS, SImode, operands)" "sbb{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") (set_attr "pent_pair" "pu") + (set_attr "ppro_uops" "few") (set_attr "mode" "SI")]) (define_expand "subsi3" [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") (minus:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:SI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "ix86_expand_binary_operator (MINUS, SImode, operands); DONE;") @@ -6649,7 +6747,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") (match_operand:SI 2 "general_operand" "ri,rm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (MINUS, SImode, operands)" "sub{l}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") @@ -6660,14 +6758,14 @@ (zero_extend:DI (minus:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "general_operand" "rim")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (MINUS, SImode, operands)" "sub{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "*subsi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") (match_operand:SI 2 "general_operand" "ri,rm")) @@ -6681,7 +6779,7 @@ (set_attr "mode" "SI")]) (define_insn "*subsi_2_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (minus:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "general_operand" "rim")) @@ -6697,7 +6795,7 @@ (set_attr "mode" "SI")]) (define_insn "*subsi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:SI 1 "nonimmediate_operand" "0,0") (match_operand:SI 2 "general_operand" "ri,rm"))) (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") @@ -6709,7 +6807,7 @@ (set_attr "mode" "SI")]) (define_insn "*subsi_3_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "general_operand" "rim"))) (set (match_operand:DI 0 "register_operand" "=r") @@ -6718,7 +6816,7 @@ (match_dup 2))))] "TARGET_64BIT && ix86_match_ccmode (insn, CCmode) && ix86_binary_operator_ok (MINUS, SImode, operands)" - "sub{l}\t{%2, %1|%1, %2}" + "sub{q}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "mode" "DI")]) @@ -6726,7 +6824,7 @@ [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "") (minus:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_HIMODE_MATH" "ix86_expand_binary_operator (MINUS, HImode, operands); DONE;") @@ -6734,14 +6832,14 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") (match_operand:HI 2 "general_operand" "ri,rm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (MINUS, HImode, operands)" "sub{w}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "mode" "HI")]) (define_insn "*subhi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") (match_operand:HI 2 "general_operand" "ri,rm")) @@ -6755,7 +6853,7 @@ (set_attr "mode" "HI")]) (define_insn "*subhi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:HI 1 "nonimmediate_operand" "0,0") (match_operand:HI 2 "general_operand" "ri,rm"))) (set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") @@ -6770,7 +6868,7 @@ [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "") (minus:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_QIMODE_MATH" "ix86_expand_binary_operator (MINUS, QImode, operands); DONE;") @@ -6778,7 +6876,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "general_operand" "qn,qmn"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (MINUS, QImode, operands)" "sub{b}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") @@ -6788,7 +6886,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) (minus:QI (match_dup 0) (match_operand:QI 1 "general_operand" "qn,qmn"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "sub{b}\t{%1, %0|%0, %1}" @@ -6796,7 +6894,7 @@ (set_attr "mode" "QI")]) (define_insn "*subqi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "general_operand" "qi,qm")) @@ -6810,7 +6908,7 @@ (set_attr "mode" "QI")]) (define_insn "*subqi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (match_operand:QI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "general_operand" "qi,qm"))) (set (match_operand:HI 0 "nonimmediate_operand" "=qm,q") @@ -6850,7 +6948,7 @@ [(parallel [(set (match_operand:DI 0 "register_operand" "") (mult:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "x86_64_general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_64BIT" "") @@ -6858,7 +6956,7 @@ [(set (match_operand:DI 0 "register_operand" "=r,r,r") (mult:DI (match_operand:DI 1 "nonimmediate_operand" "%rm,rm,0") (match_operand:DI 2 "x86_64_general_operand" "K,e,mr"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "@ @@ -6882,7 +6980,7 @@ [(parallel [(set (match_operand:SI 0 "register_operand" "") (mult:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") @@ -6890,7 +6988,7 @@ [(set (match_operand:SI 0 "register_operand" "=r,r,r") (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%rm,rm,0") (match_operand:SI 2 "general_operand" "K,i,mr"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM" "@ imul{l}\t{%2, %1, %0|%0, %1, %2} @@ -6914,7 +7012,7 @@ (zero_extend:DI (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%rm,rm,0") (match_operand:SI 2 "general_operand" "K,i,mr")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "@ @@ -6938,7 +7036,7 @@ [(parallel [(set (match_operand:HI 0 "register_operand" "") (mult:HI (match_operand:HI 1 "register_operand" "") (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_HIMODE_MATH" "") @@ -6946,7 +7044,7 @@ [(set (match_operand:HI 0 "register_operand" "=r,r,r") (mult:HI (match_operand:HI 1 "nonimmediate_operand" "%rm,rm,0") (match_operand:HI 2 "general_operand" "K,i,mr"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM" "@ imul{w}\t{%2, %1, %0|%0, %1, %2} @@ -6966,7 +7064,7 @@ [(parallel [(set (match_operand:QI 0 "register_operand" "") (mult:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_QIMODE_MATH" "") @@ -6974,7 +7072,7 @@ [(set (match_operand:QI 0 "register_operand" "=a") (mult:QI (match_operand:QI 1 "nonimmediate_operand" "%0") (match_operand:QI 2 "nonimmediate_operand" "qm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "mul{b}\t%2" @@ -6992,7 +7090,7 @@ (match_operand:QI 1 "nonimmediate_operand" "")) (zero_extend:HI (match_operand:QI 2 "register_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_QIMODE_MATH" "") @@ -7000,7 +7098,7 @@ [(set (match_operand:HI 0 "register_operand" "=a") (mult:HI (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0")) (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "mul{b}\t%2" @@ -7016,7 +7114,7 @@ [(parallel [(set (match_operand:HI 0 "register_operand" "") (mult:HI (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")) (sign_extend:HI (match_operand:QI 2 "register_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_QIMODE_MATH" "") @@ -7024,7 +7122,7 @@ [(set (match_operand:HI 0 "register_operand" "=a") (mult:HI (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0")) (sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "imul{b}\t%2" @@ -7042,7 +7140,7 @@ (match_operand:DI 1 "nonimmediate_operand" "")) (zero_extend:TI (match_operand:DI 2 "register_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_64BIT" "") @@ -7050,11 +7148,12 @@ [(set (match_operand:TI 0 "register_operand" "=A") (mult:TI (zero_extend:TI (match_operand:DI 1 "nonimmediate_operand" "%0")) (zero_extend:TI (match_operand:DI 2 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "mul{q}\t%2" [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") (set_attr "length_immediate" "0") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") @@ -7069,7 +7168,7 @@ (match_operand:SI 1 "nonimmediate_operand" "")) (zero_extend:DI (match_operand:SI 2 "register_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "!TARGET_64BIT" "") @@ -7077,11 +7176,12 @@ [(set (match_operand:DI 0 "register_operand" "=A") (mult:DI (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "%0")) (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "mul{l}\t%2" [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") (set_attr "length_immediate" "0") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") @@ -7095,7 +7195,7 @@ (match_operand:DI 1 "nonimmediate_operand" "")) (sign_extend:TI (match_operand:DI 2 "register_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_64BIT" "") @@ -7103,7 +7203,7 @@ [(set (match_operand:TI 0 "register_operand" "=A") (mult:TI (sign_extend:TI (match_operand:DI 1 "nonimmediate_operand" "%0")) (sign_extend:TI (match_operand:DI 2 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "imul{q}\t%2" @@ -7121,7 +7221,7 @@ (match_operand:SI 1 "nonimmediate_operand" "")) (sign_extend:DI (match_operand:SI 2 "register_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "!TARGET_64BIT" "") @@ -7129,7 +7229,7 @@ [(set (match_operand:DI 0 "register_operand" "=A") (mult:DI (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "%0")) (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "imul{l}\t%2" @@ -7151,7 +7251,7 @@ (match_operand:DI 2 "register_operand" ""))) (const_int 64)))) (clobber (match_scratch:DI 3 "")) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_64BIT" "") @@ -7165,11 +7265,12 @@ (match_operand:DI 2 "nonimmediate_operand" "rm"))) (const_int 64)))) (clobber (match_scratch:DI 3 "=1")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "mul{q}\t%2" [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") (set_attr "length_immediate" "0") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") @@ -7187,7 +7288,7 @@ (match_operand:SI 2 "register_operand" ""))) (const_int 32)))) (clobber (match_scratch:SI 3 "")) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") @@ -7201,10 +7302,11 @@ (match_operand:SI 2 "nonimmediate_operand" "rm"))) (const_int 32)))) (clobber (match_scratch:SI 3 "=1")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM" "mul{l}\t%2" [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") (set_attr "length_immediate" "0") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") @@ -7222,11 +7324,12 @@ (match_operand:SI 2 "nonimmediate_operand" "rm"))) (const_int 32))))) (clobber (match_scratch:SI 3 "=1")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "mul{l}\t%2" [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") (set_attr "length_immediate" "0") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") @@ -7244,7 +7347,7 @@ (match_operand:DI 2 "register_operand" ""))) (const_int 64)))) (clobber (match_scratch:DI 3 "")) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_64BIT" "") @@ -7258,11 +7361,12 @@ (match_operand:DI 2 "nonimmediate_operand" "rm"))) (const_int 64)))) (clobber (match_scratch:DI 3 "=1")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "imul{q}\t%2" [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") (const_string "vector") @@ -7279,7 +7383,7 @@ (match_operand:SI 2 "register_operand" ""))) (const_int 32)))) (clobber (match_scratch:SI 3 "")) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") @@ -7293,10 +7397,11 @@ (match_operand:SI 2 "nonimmediate_operand" "rm"))) (const_int 32)))) (clobber (match_scratch:SI 3 "=1")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM" "imul{l}\t%2" [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") (const_string "vector") @@ -7313,11 +7418,12 @@ (match_operand:SI 2 "nonimmediate_operand" "rm"))) (const_int 32))))) (clobber (match_scratch:SI 3 "=1")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "imul{l}\t%2" [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") (const_string "vector") @@ -7353,21 +7459,23 @@ [(set (match_operand:QI 0 "register_operand" "=a") (div:QI (match_operand:HI 1 "register_operand" "0") (match_operand:QI 2 "nonimmediate_operand" "qm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH" "idiv{b}\t%2" [(set_attr "type" "idiv") - (set_attr "mode" "QI")]) + (set_attr "mode" "QI") + (set_attr "ppro_uops" "few")]) (define_insn "udivqi3" [(set (match_operand:QI 0 "register_operand" "=a") (udiv:QI (match_operand:HI 1 "register_operand" "0") (match_operand:QI 2 "nonimmediate_operand" "qm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH" "div{b}\t%2" [(set_attr "type" "idiv") - (set_attr "mode" "QI")]) + (set_attr "mode" "QI") + (set_attr "ppro_uops" "few")]) ;; The patterns that match these are at the end of this file. @@ -7400,7 +7508,7 @@ (match_operand:DI 2 "nonimmediate_operand" ""))) (set (match_operand:DI 3 "register_operand" "") (mod:DI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_64BIT" "") @@ -7413,7 +7521,7 @@ (match_operand:DI 3 "nonimmediate_operand" "rm,rm"))) (set (match_operand:DI 1 "register_operand" "=&d,&d") (mod:DI (match_dup 2) (match_dup 3))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && !optimize_size && !TARGET_USE_CLTD" "#" [(set_attr "type" "multi")]) @@ -7424,7 +7532,7 @@ (match_operand:DI 3 "nonimmediate_operand" "rm"))) (set (match_operand:DI 1 "register_operand" "=&d") (mod:DI (match_dup 2) (match_dup 3))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (optimize_size || TARGET_USE_CLTD)" "#" [(set_attr "type" "multi")]) @@ -7436,11 +7544,12 @@ (set (match_operand:DI 3 "register_operand" "=d") (mod:DI (match_dup 1) (match_dup 2))) (use (match_operand:DI 4 "register_operand" "3")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "idiv{q}\t%2" [(set_attr "type" "idiv") - (set_attr "mode" "DI")]) + (set_attr "mode" "DI") + (set_attr "ppro_uops" "few")]) (define_split [(set (match_operand:DI 0 "register_operand" "") @@ -7448,17 +7557,17 @@ (match_operand:DI 2 "nonimmediate_operand" ""))) (set (match_operand:DI 3 "register_operand" "") (mod:DI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && reload_completed" [(parallel [(set (match_dup 3) (ashiftrt:DI (match_dup 4) (const_int 63))) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (parallel [(set (match_dup 0) (div:DI (reg:DI 0) (match_dup 2))) (set (match_dup 3) (mod:DI (reg:DI 0) (match_dup 2))) (use (match_dup 3)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] { /* Avoid use of cltd in favor of a mov+shift. */ if (!TARGET_USE_CLTD && !optimize_size) @@ -7471,7 +7580,8 @@ } else { - gcc_assert (!true_regnum (operands[1])); + if (true_regnum (operands[1])) + abort(); operands[4] = operands[1]; } }) @@ -7483,7 +7593,7 @@ (match_operand:SI 2 "nonimmediate_operand" ""))) (set (match_operand:SI 3 "register_operand" "") (mod:SI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") @@ -7496,7 +7606,7 @@ (match_operand:SI 3 "nonimmediate_operand" "rm,rm"))) (set (match_operand:SI 1 "register_operand" "=&d,&d") (mod:SI (match_dup 2) (match_dup 3))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!optimize_size && !TARGET_USE_CLTD" "#" [(set_attr "type" "multi")]) @@ -7507,7 +7617,7 @@ (match_operand:SI 3 "nonimmediate_operand" "rm"))) (set (match_operand:SI 1 "register_operand" "=&d") (mod:SI (match_dup 2) (match_dup 3))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "optimize_size || TARGET_USE_CLTD" "#" [(set_attr "type" "multi")]) @@ -7519,11 +7629,12 @@ (set (match_operand:SI 3 "register_operand" "=d") (mod:SI (match_dup 1) (match_dup 2))) (use (match_operand:SI 4 "register_operand" "3")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "idiv{l}\t%2" [(set_attr "type" "idiv") - (set_attr "mode" "SI")]) + (set_attr "mode" "SI") + (set_attr "ppro_uops" "few")]) (define_split [(set (match_operand:SI 0 "register_operand" "") @@ -7531,17 +7642,17 @@ (match_operand:SI 2 "nonimmediate_operand" ""))) (set (match_operand:SI 3 "register_operand" "") (mod:SI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed" [(parallel [(set (match_dup 3) (ashiftrt:SI (match_dup 4) (const_int 31))) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (parallel [(set (match_dup 0) (div:SI (reg:SI 0) (match_dup 2))) (set (match_dup 3) (mod:SI (reg:SI 0) (match_dup 2))) (use (match_dup 3)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] { /* Avoid use of cltd in favor of a mov+shift. */ if (!TARGET_USE_CLTD && !optimize_size) @@ -7554,7 +7665,8 @@ } else { - gcc_assert (!true_regnum (operands[1])); + if (true_regnum (operands[1])) + abort(); operands[4] = operands[1]; } }) @@ -7565,7 +7677,7 @@ (match_operand:HI 2 "nonimmediate_operand" "rm"))) (set (match_operand:HI 3 "register_operand" "=&d") (mod:HI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_HIMODE_MATH" "cwtd\;idiv{w}\t%2" [(set_attr "type" "multi") @@ -7578,7 +7690,7 @@ (match_operand:DI 2 "nonimmediate_operand" "rm"))) (set (match_operand:DI 3 "register_operand" "=&d") (umod:DI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "xor{q}\t%3, %3\;div{q}\t%2" [(set_attr "type" "multi") @@ -7592,10 +7704,11 @@ (set (match_operand:DI 3 "register_operand" "=d") (umod:DI (match_dup 1) (match_dup 2))) (use (match_dup 3)) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "div{q}\t%2" [(set_attr "type" "idiv") + (set_attr "ppro_uops" "few") (set_attr "mode" "DI")]) (define_split @@ -7604,7 +7717,7 @@ (match_operand:DI 2 "nonimmediate_operand" ""))) (set (match_operand:DI 3 "register_operand" "") (umod:DI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && reload_completed" [(set (match_dup 3) (const_int 0)) (parallel [(set (match_dup 0) @@ -7612,7 +7725,7 @@ (set (match_dup 3) (umod:DI (match_dup 1) (match_dup 2))) (use (match_dup 3)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_insn "udivmodsi4" @@ -7621,7 +7734,7 @@ (match_operand:SI 2 "nonimmediate_operand" "rm"))) (set (match_operand:SI 3 "register_operand" "=&d") (umod:SI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "xor{l}\t%3, %3\;div{l}\t%2" [(set_attr "type" "multi") @@ -7635,10 +7748,11 @@ (set (match_operand:SI 3 "register_operand" "=d") (umod:SI (match_dup 1) (match_dup 2))) (use (match_dup 3)) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "div{l}\t%2" [(set_attr "type" "idiv") + (set_attr "ppro_uops" "few") (set_attr "mode" "SI")]) (define_split @@ -7647,7 +7761,7 @@ (match_operand:SI 2 "nonimmediate_operand" ""))) (set (match_operand:SI 3 "register_operand" "") (umod:SI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed" [(set (match_dup 3) (const_int 0)) (parallel [(set (match_dup 0) @@ -7655,7 +7769,7 @@ (set (match_dup 3) (umod:SI (match_dup 1) (match_dup 2))) (use (match_dup 3)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_expand "udivmodhi4" @@ -7666,7 +7780,7 @@ (set (match_operand:HI 3 "register_operand" "") (umod:HI (match_dup 1) (match_dup 2))) (use (match_dup 4)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_HIMODE_MATH" "operands[4] = gen_reg_rtx (HImode);") @@ -7677,13 +7791,14 @@ (set (match_operand:HI 3 "register_operand" "=d") (umod:HI (match_dup 1) (match_dup 2))) (use (match_operand:HI 4 "register_operand" "3")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "div{w}\t%2" [(set_attr "type" "idiv") - (set_attr "mode" "HI")]) + (set_attr "mode" "HI") + (set_attr "ppro_uops" "few")]) -;; We cannot use div/idiv for double division, because it causes +;; We can not use div/idiv for double division, because it causes ;; "division by zero" on the overflow and that's not what we expect ;; from truncate. Because true (non truncating) double division is ;; never generated, we can't create this insn anyway. @@ -7697,10 +7812,11 @@ ; (set (match_operand:SI 3 "register_operand" "=d") ; (truncate:SI ; (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2))))) -; (clobber (reg:CC FLAGS_REG))] +; (clobber (reg:CC 17))] ; "" ; "div{l}\t{%2, %0|%0, %2}" -; [(set_attr "type" "idiv")]) +; [(set_attr "type" "idiv") +; (set_attr "ppro_uops" "few")]) ;;- Logical AND instructions @@ -7708,7 +7824,7 @@ ;; Note that this excludes ah. (define_insn "*testdi_1_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:DI (match_operand:DI 0 "nonimmediate_operand" "%!*a,r,!*a,r,rm") (match_operand:DI 1 "x86_64_szext_general_operand" "Z,Z,e,e,re")) @@ -7716,10 +7832,10 @@ "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "@ - test{l}\t{%k1, %k0|%k0, %k1} - test{l}\t{%k1, %k0|%k0, %k1} - test{q}\t{%1, %0|%0, %1} - test{q}\t{%1, %0|%0, %1} + test{l}\t{%k1, %k0|%k0, %k1} + test{l}\t{%k1, %k0|%k0, %k1} + test{q}\t{%1, %0|%0, %1} + test{q}\t{%1, %0|%0, %1} test{q}\t{%1, %0|%0, %1}" [(set_attr "type" "test") (set_attr "modrm" "0,1,0,1,1") @@ -7727,7 +7843,7 @@ (set_attr "pent_pair" "uv,np,uv,np,uv")]) (define_insn "testsi_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:SI (match_operand:SI 0 "nonimmediate_operand" "%!*a,r,rm") (match_operand:SI 1 "general_operand" "in,in,rin")) @@ -7741,7 +7857,7 @@ (set_attr "pent_pair" "uv,np,uv")]) (define_expand "testsi_ccno_1" - [(set (reg:CCNO FLAGS_REG) + [(set (reg:CCNO 17) (compare:CCNO (and:SI (match_operand:SI 0 "nonimmediate_operand" "") (match_operand:SI 1 "nonmemory_operand" "")) @@ -7750,7 +7866,7 @@ "") (define_insn "*testhi_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:HI (match_operand:HI 0 "nonimmediate_operand" "%!*a,r,rm") (match_operand:HI 1 "general_operand" "n,n,rn")) (const_int 0)))] @@ -7763,7 +7879,7 @@ (set_attr "pent_pair" "uv,np,uv")]) (define_expand "testqi_ccz_1" - [(set (reg:CCZ FLAGS_REG) + [(set (reg:CCZ 17) (compare:CCZ (and:QI (match_operand:QI 0 "nonimmediate_operand" "") (match_operand:QI 1 "nonmemory_operand" "")) (const_int 0)))] @@ -7771,16 +7887,16 @@ "") (define_insn "*testqi_1_maybe_si" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:QI (match_operand:QI 0 "nonimmediate_operand" "%!*a,q,qm,r") (match_operand:QI 1 "general_operand" "n,n,qn,n")) (const_int 0)))] - "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) - && ix86_match_ccmode (insn, - GET_CODE (operands[1]) == CONST_INT - && INTVAL (operands[1]) >= 0 ? CCNOmode : CCZmode)" + "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && ix86_match_ccmode (insn, + GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= 0 ? CCNOmode : CCZmode)" { if (which_alternative == 3) { @@ -7796,7 +7912,7 @@ (set_attr "pent_pair" "uv,np,uv,np")]) (define_insn "*testqi_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:QI (match_operand:QI 0 "nonimmediate_operand" "%!*a,q,qm") @@ -7811,7 +7927,7 @@ (set_attr "pent_pair" "uv,np,uv")]) (define_expand "testqi_ext_ccno_0" - [(set (reg:CCNO FLAGS_REG) + [(set (reg:CCNO 17) (compare:CCNO (and:SI (zero_extract:SI @@ -7824,7 +7940,7 @@ "") (define_insn "*testqi_ext_0" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:SI (zero_extract:SI @@ -7841,7 +7957,7 @@ (set_attr "pent_pair" "np")]) (define_insn "*testqi_ext_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:SI (zero_extract:SI @@ -7858,7 +7974,7 @@ (set_attr "mode" "QI")]) (define_insn "*testqi_ext_1_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:SI (zero_extract:SI @@ -7874,7 +7990,7 @@ (set_attr "mode" "QI")]) (define_insn "*testqi_ext_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:SI (zero_extract:SI @@ -7893,16 +8009,13 @@ ;; Combine likes to form bit extractions for some tests. Humor it. (define_insn "*testqi_ext_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (zero_extract:SI (match_operand 0 "nonimmediate_operand" "rm") (match_operand:SI 1 "const_int_operand" "") (match_operand:SI 2 "const_int_operand" "")) (const_int 0)))] "ix86_match_ccmode (insn, CCNOmode) - && INTVAL (operands[1]) > 0 - && INTVAL (operands[2]) >= 0 - && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32 && (GET_MODE (operands[0]) == SImode || (TARGET_64BIT && GET_MODE (operands[0]) == DImode) || GET_MODE (operands[0]) == HImode @@ -7910,7 +8023,7 @@ "#") (define_insn "*testqi_ext_3_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (zero_extract:DI (match_operand 0 "nonimmediate_operand" "rm") (match_operand:DI 1 "const_int_operand" "") @@ -7918,8 +8031,8 @@ (const_int 0)))] "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && INTVAL (operands[1]) > 0 - && INTVAL (operands[2]) >= 0 + /* The code below cannot deal with constants outside HOST_WIDE_INT. */ + && INTVAL (operands[1]) + INTVAL (operands[2]) < HOST_BITS_PER_WIDE_INT /* Ensure that resulting mask is zero or sign extended operand. */ && (INTVAL (operands[1]) + INTVAL (operands[2]) <= 32 || (INTVAL (operands[1]) + INTVAL (operands[2]) == 64 @@ -7974,11 +8087,8 @@ val = gen_lowpart (QImode, val); } - if (len == HOST_BITS_PER_WIDE_INT) - mask = -1; - else - mask = ((HOST_WIDE_INT)1 << len) - 1; - mask <<= pos; + mask = ((HOST_WIDE_INT)1 << (pos + len)) - 1; + mask &= ~(((HOST_WIDE_INT)1 << pos) - 1); operands[2] = gen_rtx_AND (mode, val, gen_int_mode (mask, mode)); }) @@ -8037,7 +8147,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "") (and:DI (match_operand:DI 1 "nonimmediate_operand" "") (match_operand:DI 2 "x86_64_szext_general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "ix86_expand_binary_operator (AND, DImode, operands); DONE;") @@ -8045,7 +8155,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,rm,r,r") (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0,qm") (match_operand:DI 2 "x86_64_szext_general_operand" "Z,re,rm,L"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (AND, DImode, operands)" { switch (get_attr_type (insn)) @@ -8054,14 +8164,14 @@ { enum machine_mode mode; - gcc_assert (GET_CODE (operands[2]) == CONST_INT); + if (GET_CODE (operands[2]) != CONST_INT) + abort (); if (INTVAL (operands[2]) == 0xff) mode = QImode; + else if (INTVAL (operands[2]) == 0xffff) + mode = HImode; else - { - gcc_assert (INTVAL (operands[2]) == 0xffff); - mode = HImode; - } + abort (); operands[1] = gen_lowpart (mode, operands[1]); if (mode == QImode) @@ -8071,7 +8181,8 @@ } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); if (get_attr_mode (insn) == MODE_SI) return "and{l}\t{%k2, %k0|%k0, %k2}"; else @@ -8083,7 +8194,7 @@ (set_attr "mode" "SI,DI,DI,DI")]) (define_insn "*anddi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0") (match_operand:DI 2 "x86_64_szext_general_operand" "Z,rem,re")) (const_int 0))) @@ -8092,8 +8203,8 @@ "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) && ix86_binary_operator_ok (AND, DImode, operands)" "@ - and{l}\t{%k2, %k0|%k0, %k2} - and{q}\t{%2, %0|%0, %2} + and{l}\t{%k2, %k0|%k0, %k2} + and{q}\t{%2, %0|%0, %2} and{q}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "mode" "SI,DI,DI")]) @@ -8102,7 +8213,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "") (and:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:SI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "ix86_expand_binary_operator (AND, SImode, operands); DONE;") @@ -8110,7 +8221,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r,r") (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,qm") (match_operand:SI 2 "general_operand" "ri,rm,L"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (AND, SImode, operands)" { switch (get_attr_type (insn)) @@ -8119,14 +8230,14 @@ { enum machine_mode mode; - gcc_assert (GET_CODE (operands[2]) == CONST_INT); + if (GET_CODE (operands[2]) != CONST_INT) + abort (); if (INTVAL (operands[2]) == 0xff) mode = QImode; + else if (INTVAL (operands[2]) == 0xffff) + mode = HImode; else - { - gcc_assert (INTVAL (operands[2]) == 0xffff); - mode = HImode; - } + abort (); operands[1] = gen_lowpart (mode, operands[1]); if (mode == QImode) @@ -8136,7 +8247,8 @@ } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); return "and{l}\t{%2, %0|%0, %2}"; } } @@ -8148,7 +8260,7 @@ [(set (match_operand 0 "register_operand" "") (and (match_dup 0) (const_int -65536))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "optimize_size || (TARGET_FAST_PREFIX && !TARGET_PARTIAL_REG_STALL)" [(set (strict_low_part (match_dup 1)) (const_int 0))] "operands[1] = gen_lowpart (HImode, operands[0]);") @@ -8157,7 +8269,7 @@ [(set (match_operand 0 "ext_register_operand" "") (and (match_dup 0) (const_int -256))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(optimize_size || !TARGET_PARTIAL_REG_STALL) && reload_completed" [(set (strict_low_part (match_dup 1)) (const_int 0))] "operands[1] = gen_lowpart (QImode, operands[0]);") @@ -8166,7 +8278,7 @@ [(set (match_operand 0 "ext_register_operand" "") (and (match_dup 0) (const_int -65281))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(optimize_size || !TARGET_PARTIAL_REG_STALL) && reload_completed" [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 8) @@ -8178,7 +8290,7 @@ (zero_extract:SI (match_dup 0) (const_int 8) (const_int 8)))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[0] = gen_lowpart (SImode, operands[0]);") ;; See comment for addsi_1_zext why we do use nonimmediate_operand @@ -8187,14 +8299,14 @@ (zero_extend:DI (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand:SI 2 "general_operand" "rim")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (AND, SImode, operands)" "and{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "*andsi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") (match_operand:SI 2 "general_operand" "rim,ri")) (const_int 0))) @@ -8208,7 +8320,7 @@ ;; See comment for addsi_1_zext why we do use nonimmediate_operand (define_insn "*andsi_2_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand:SI 2 "general_operand" "rim")) (const_int 0))) @@ -8224,7 +8336,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "") (and:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_HIMODE_MATH" "ix86_expand_binary_operator (AND, HImode, operands); DONE;") @@ -8232,18 +8344,21 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r") (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,qm") (match_operand:HI 2 "general_operand" "ri,rm,L"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (AND, HImode, operands)" { switch (get_attr_type (insn)) { case TYPE_IMOVX: - gcc_assert (GET_CODE (operands[2]) == CONST_INT); - gcc_assert (INTVAL (operands[2]) == 0xff); - return "movz{bl|x}\t{%b1, %k0|%k0, %b1}"; + if (GET_CODE (operands[2]) != CONST_INT) + abort (); + if (INTVAL (operands[2]) == 0xff) + return "movz{bl|x}\t{%b1, %k0|%k0, %b1}"; + abort (); default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (! rtx_equal_p (operands[0], operands[1])) + abort (); return "and{w}\t{%2, %0|%0, %2}"; } @@ -8253,7 +8368,7 @@ (set_attr "mode" "HI,HI,SI")]) (define_insn "*andhi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") (match_operand:HI 2 "general_operand" "rim,ri")) (const_int 0))) @@ -8269,7 +8384,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "") (and:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH" "ix86_expand_binary_operator (AND, QImode, operands); DONE;") @@ -8278,7 +8393,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r") (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") (match_operand:QI 2 "general_operand" "qi,qmi,ri"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (AND, QImode, operands)" "@ and{b}\t{%2, %0|%0, %2} @@ -8291,7 +8406,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) (and:QI (match_dup 0) (match_operand:QI 1 "general_operand" "qi,qmi"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "and{b}\t{%1, %0|%0, %1}" @@ -8299,7 +8414,7 @@ (set_attr "mode" "QI")]) (define_insn "*andqi_2_maybe_si" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") (match_operand:QI 2 "general_operand" "qim,qi,i")) @@ -8323,7 +8438,7 @@ (set_attr "mode" "QI,QI,SI")]) (define_insn "*andqi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") (match_operand:QI 2 "general_operand" "qim,qi")) @@ -8337,7 +8452,7 @@ (set_attr "mode" "QI")]) (define_insn "*andqi_2_slp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:QI (match_operand:QI 0 "nonimmediate_operand" "+q,qm") (match_operand:QI 1 "nonimmediate_operand" "qmi,qi")) @@ -8365,7 +8480,7 @@ (const_int 8) (const_int 8)) (match_operand 2 "const_int_operand" "n"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "and{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") @@ -8376,7 +8491,7 @@ ;; often in fp comparisons. (define_insn "*andqi_ext_0_cc" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (and:SI (zero_extract:SI @@ -8411,7 +8526,7 @@ (const_int 8)) (zero_extend:SI (match_operand:QI 2 "general_operand" "Qm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT" "and{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") @@ -8429,7 +8544,7 @@ (const_int 8)) (zero_extend:SI (match_operand 2 "ext_register_operand" "Q")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "and{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") @@ -8449,7 +8564,7 @@ (match_operand 2 "ext_register_operand" "Q") (const_int 8) (const_int 8)))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "and{b}\t{%h2, %h0|%h0, %h2}" [(set_attr "type" "alu") @@ -8465,7 +8580,7 @@ [(set (match_operand 0 "register_operand" "") (and (match_operand 1 "register_operand" "") (match_operand 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && QI_REG_P (operands[0]) && (!TARGET_PARTIAL_REG_STALL || optimize_size) @@ -8475,7 +8590,7 @@ (and:SI (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8)) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[0] = gen_lowpart (SImode, operands[0]); operands[1] = gen_lowpart (SImode, operands[1]); operands[2] = gen_int_mode ((INTVAL (operands[2]) >> 8) & 0xff, SImode);") @@ -8486,7 +8601,7 @@ [(set (match_operand 0 "register_operand" "") (and (match_operand 1 "general_operand" "") (match_operand 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && ANY_QI_REG_P (operands[0]) && (!TARGET_PARTIAL_REG_STALL || optimize_size) @@ -8496,7 +8611,7 @@ [(parallel [(set (strict_low_part (match_dup 0)) (and:QI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[0] = gen_lowpart (QImode, operands[0]); operands[1] = gen_lowpart (QImode, operands[1]); operands[2] = gen_lowpart (QImode, operands[2]);") @@ -8510,7 +8625,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "") (ior:DI (match_operand:DI 1 "nonimmediate_operand" "") (match_operand:DI 2 "x86_64_general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "ix86_expand_binary_operator (IOR, DImode, operands); DONE;") @@ -8518,7 +8633,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") (match_operand:DI 2 "x86_64_general_operand" "re,rme"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (IOR, DImode, operands)" "or{q}\t{%2, %0|%0, %2}" @@ -8526,7 +8641,7 @@ (set_attr "mode" "DI")]) (define_insn "*iordi_2_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") (match_operand:DI 2 "x86_64_general_operand" "rem,re")) (const_int 0))) @@ -8540,7 +8655,7 @@ (set_attr "mode" "DI")]) (define_insn "*iordi_3_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0") (match_operand:DI 2 "x86_64_general_operand" "rem")) (const_int 0))) @@ -8557,7 +8672,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "") (ior:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:SI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "ix86_expand_binary_operator (IOR, SImode, operands); DONE;") @@ -8565,7 +8680,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") (match_operand:SI 2 "general_operand" "ri,rmi"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (IOR, SImode, operands)" "or{l}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") @@ -8577,7 +8692,7 @@ (zero_extend:DI (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand:SI 2 "general_operand" "rim")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (IOR, SImode, operands)" "or{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") @@ -8587,14 +8702,14 @@ [(set (match_operand:DI 0 "register_operand" "=rm") (ior:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) (match_operand:DI 2 "x86_64_zext_immediate_operand" "Z"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "or{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "*iorsi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") (match_operand:SI 2 "general_operand" "rim,ri")) (const_int 0))) @@ -8609,7 +8724,7 @@ ;; See comment for addsi_1_zext why we do use nonimmediate_operand ;; ??? Special case for immediate operand is missing - it is tricky. (define_insn "*iorsi_2_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand:SI 2 "general_operand" "rim")) (const_int 0))) @@ -8622,7 +8737,7 @@ (set_attr "mode" "SI")]) (define_insn "*iorsi_2_zext_imm" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand 2 "x86_64_zext_immediate_operand" "Z")) (const_int 0))) @@ -8635,7 +8750,7 @@ (set_attr "mode" "SI")]) (define_insn "*iorsi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand:SI 2 "general_operand" "rim")) (const_int 0))) @@ -8650,7 +8765,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "") (ior:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_HIMODE_MATH" "ix86_expand_binary_operator (IOR, HImode, operands); DONE;") @@ -8658,14 +8773,14 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,m") (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") (match_operand:HI 2 "general_operand" "rmi,ri"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (IOR, HImode, operands)" "or{w}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "mode" "HI")]) (define_insn "*iorhi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") (match_operand:HI 2 "general_operand" "rim,ri")) (const_int 0))) @@ -8678,7 +8793,7 @@ (set_attr "mode" "HI")]) (define_insn "*iorhi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0") (match_operand:HI 2 "general_operand" "rim")) (const_int 0))) @@ -8693,7 +8808,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "") (ior:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH" "ix86_expand_binary_operator (IOR, QImode, operands); DONE;") @@ -8702,7 +8817,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,r") (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") (match_operand:QI 2 "general_operand" "qmi,qi,ri"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (IOR, QImode, operands)" "@ or{b}\t{%2, %0|%0, %2} @@ -8715,7 +8830,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+q,m")) (ior:QI (match_dup 0) (match_operand:QI 1 "general_operand" "qmi,qi"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "or{b}\t{%1, %0|%0, %1}" @@ -8723,7 +8838,7 @@ (set_attr "mode" "QI")]) (define_insn "*iorqi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") (match_operand:QI 2 "general_operand" "qim,qi")) (const_int 0))) @@ -8736,7 +8851,7 @@ (set_attr "mode" "QI")]) (define_insn "*iorqi_2_slp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:QI (match_operand:QI 0 "nonimmediate_operand" "+q,qm") (match_operand:QI 1 "general_operand" "qim,qi")) (const_int 0))) @@ -8750,7 +8865,7 @@ (set_attr "mode" "QI")]) (define_insn "*iorqi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0") (match_operand:QI 2 "general_operand" "qim")) (const_int 0))) @@ -8771,7 +8886,7 @@ (const_int 8) (const_int 8)) (match_operand 2 "const_int_operand" "n"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(!TARGET_PARTIAL_REG_STALL || optimize_size)" "or{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") @@ -8789,7 +8904,7 @@ (const_int 8)) (zero_extend:SI (match_operand:QI 2 "general_operand" "Qm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && (!TARGET_PARTIAL_REG_STALL || optimize_size)" "or{b}\t{%2, %h0|%h0, %2}" @@ -8808,7 +8923,7 @@ (const_int 8)) (zero_extend:SI (match_operand 2 "ext_register_operand" "Q")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (!TARGET_PARTIAL_REG_STALL || optimize_size)" "or{b}\t{%2, %h0|%h0, %2}" @@ -8827,7 +8942,7 @@ (zero_extract:SI (match_operand 2 "ext_register_operand" "Q") (const_int 8) (const_int 8)))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(!TARGET_PARTIAL_REG_STALL || optimize_size)" "ior{b}\t{%h2, %h0|%h0, %h2}" [(set_attr "type" "alu") @@ -8838,7 +8953,7 @@ [(set (match_operand 0 "register_operand" "") (ior (match_operand 1 "register_operand" "") (match_operand 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && QI_REG_P (operands[0]) && (!TARGET_PARTIAL_REG_STALL || optimize_size) @@ -8848,7 +8963,7 @@ (ior:SI (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8)) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[0] = gen_lowpart (SImode, operands[0]); operands[1] = gen_lowpart (SImode, operands[1]); operands[2] = gen_int_mode ((INTVAL (operands[2]) >> 8) & 0xff, SImode);") @@ -8859,7 +8974,7 @@ [(set (match_operand 0 "register_operand" "") (ior (match_operand 1 "general_operand" "") (match_operand 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && ANY_QI_REG_P (operands[0]) && (!TARGET_PARTIAL_REG_STALL || optimize_size) @@ -8869,7 +8984,7 @@ [(parallel [(set (strict_low_part (match_dup 0)) (ior:QI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[0] = gen_lowpart (QImode, operands[0]); operands[1] = gen_lowpart (QImode, operands[1]); operands[2] = gen_lowpart (QImode, operands[2]);") @@ -8883,7 +8998,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "") (xor:DI (match_operand:DI 1 "nonimmediate_operand" "") (match_operand:DI 2 "x86_64_general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "ix86_expand_binary_operator (XOR, DImode, operands); DONE;") @@ -8891,17 +9006,17 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (XOR, DImode, operands)" "@ - xor{q}\t{%2, %0|%0, %2} + xor{q}\t{%2, %0|%0, %2} xor{q}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "mode" "DI,DI")]) (define_insn "*xordi_2_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") (match_operand:DI 2 "x86_64_general_operand" "rem,re")) (const_int 0))) @@ -8911,13 +9026,13 @@ && ix86_match_ccmode (insn, CCNOmode) && ix86_binary_operator_ok (XOR, DImode, operands)" "@ - xor{q}\t{%2, %0|%0, %2} + xor{q}\t{%2, %0|%0, %2} xor{q}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "mode" "DI,DI")]) (define_insn "*xordi_3_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0") (match_operand:DI 2 "x86_64_general_operand" "rem")) (const_int 0))) @@ -8933,7 +9048,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "") (xor:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:SI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "ix86_expand_binary_operator (XOR, SImode, operands); DONE;") @@ -8941,7 +9056,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") (match_operand:SI 2 "general_operand" "ri,rm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (XOR, SImode, operands)" "xor{l}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") @@ -8954,7 +9069,7 @@ (zero_extend:DI (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand:SI 2 "general_operand" "rim")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (XOR, SImode, operands)" "xor{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") @@ -8964,14 +9079,14 @@ [(set (match_operand:DI 0 "register_operand" "=r") (xor:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) (match_operand:DI 2 "x86_64_zext_immediate_operand" "Z"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (XOR, SImode, operands)" "xor{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") (set_attr "mode" "SI")]) (define_insn "*xorsi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") (match_operand:SI 2 "general_operand" "rim,ri")) (const_int 0))) @@ -8986,7 +9101,7 @@ ;; See comment for addsi_1_zext why we do use nonimmediate_operand ;; ??? Special case for immediate operand is missing - it is tricky. (define_insn "*xorsi_2_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand:SI 2 "general_operand" "rim")) (const_int 0))) @@ -8999,7 +9114,7 @@ (set_attr "mode" "SI")]) (define_insn "*xorsi_2_zext_imm" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand 2 "x86_64_zext_immediate_operand" "Z")) (const_int 0))) @@ -9012,7 +9127,7 @@ (set_attr "mode" "SI")]) (define_insn "*xorsi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") (match_operand:SI 2 "general_operand" "rim")) (const_int 0))) @@ -9027,7 +9142,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "") (xor:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_HIMODE_MATH" "ix86_expand_binary_operator (XOR, HImode, operands); DONE;") @@ -9035,14 +9150,14 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,m") (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") (match_operand:HI 2 "general_operand" "rmi,ri"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (XOR, HImode, operands)" "xor{w}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "mode" "HI")]) (define_insn "*xorhi_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") (match_operand:HI 2 "general_operand" "rim,ri")) (const_int 0))) @@ -9055,7 +9170,7 @@ (set_attr "mode" "HI")]) (define_insn "*xorhi_3" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0") (match_operand:HI 2 "general_operand" "rim")) (const_int 0))) @@ -9070,7 +9185,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "") (xor:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH" "ix86_expand_binary_operator (XOR, QImode, operands); DONE;") @@ -9079,7 +9194,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,r") (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") (match_operand:QI 2 "general_operand" "qmi,qi,ri"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (XOR, QImode, operands)" "@ xor{b}\t{%2, %0|%0, %2} @@ -9092,7 +9207,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) (xor:QI (match_dup 0) (match_operand:QI 1 "general_operand" "qi,qmi"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "xor{b}\t{%1, %0|%0, %1}" @@ -9109,7 +9224,7 @@ (const_int 8) (const_int 8)) (match_operand 2 "const_int_operand" "n"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(!TARGET_PARTIAL_REG_STALL || optimize_size)" "xor{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") @@ -9127,7 +9242,7 @@ (const_int 8)) (zero_extend:SI (match_operand:QI 2 "general_operand" "Qm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && (!TARGET_PARTIAL_REG_STALL || optimize_size)" "xor{b}\t{%2, %h0|%h0, %2}" @@ -9146,7 +9261,7 @@ (const_int 8)) (zero_extend:SI (match_operand 2 "ext_register_operand" "Q")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (!TARGET_PARTIAL_REG_STALL || optimize_size)" "xor{b}\t{%2, %h0|%h0, %2}" @@ -9165,7 +9280,7 @@ (zero_extract:SI (match_operand 2 "ext_register_operand" "Q") (const_int 8) (const_int 8)))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(!TARGET_PARTIAL_REG_STALL || optimize_size)" "xor{b}\t{%h2, %h0|%h0, %h2}" [(set_attr "type" "alu") @@ -9173,7 +9288,7 @@ (set_attr "mode" "QI")]) (define_insn "*xorqi_cc_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") (match_operand:QI 2 "general_operand" "qim,qi")) @@ -9187,7 +9302,7 @@ (set_attr "mode" "QI")]) (define_insn "*xorqi_2_slp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:QI (match_operand:QI 0 "nonimmediate_operand" "+q,qm") (match_operand:QI 1 "general_operand" "qim,qi")) (const_int 0))) @@ -9201,7 +9316,7 @@ (set_attr "mode" "QI")]) (define_insn "*xorqi_cc_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0") (match_operand:QI 2 "general_operand" "qim")) @@ -9214,7 +9329,7 @@ (set_attr "mode" "QI")]) (define_insn "*xorqi_cc_ext_1" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:SI (zero_extract:SI @@ -9235,7 +9350,7 @@ (set_attr "mode" "QI")]) (define_insn "*xorqi_cc_ext_1_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (xor:SI (zero_extract:SI @@ -9257,7 +9372,7 @@ (define_expand "xorqi_cc_ext_1" [(parallel [ - (set (reg:CCNO FLAGS_REG) + (set (reg:CCNO 17) (compare:CCNO (xor:SI (zero_extract:SI @@ -9279,7 +9394,7 @@ [(set (match_operand 0 "register_operand" "") (xor (match_operand 1 "register_operand" "") (match_operand 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && QI_REG_P (operands[0]) && (!TARGET_PARTIAL_REG_STALL || optimize_size) @@ -9289,7 +9404,7 @@ (xor:SI (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8)) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[0] = gen_lowpart (SImode, operands[0]); operands[1] = gen_lowpart (SImode, operands[1]); operands[2] = gen_int_mode ((INTVAL (operands[2]) >> 8) & 0xff, SImode);") @@ -9300,7 +9415,7 @@ [(set (match_operand 0 "register_operand" "") (xor (match_operand 1 "general_operand" "") (match_operand 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && ANY_QI_REG_P (operands[0]) && (!TARGET_PARTIAL_REG_STALL || optimize_size) @@ -9310,61 +9425,24 @@ [(parallel [(set (strict_low_part (match_dup 0)) (xor:QI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[0] = gen_lowpart (QImode, operands[0]); operands[1] = gen_lowpart (QImode, operands[1]); operands[2] = gen_lowpart (QImode, operands[2]);") ;; Negation instructions -(define_expand "negti2" - [(parallel [(set (match_operand:TI 0 "nonimmediate_operand" "") - (neg:TI (match_operand:TI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" - "ix86_expand_unary_operator (NEG, TImode, operands); DONE;") - -(define_insn "*negti2_1" - [(set (match_operand:TI 0 "nonimmediate_operand" "=ro") - (neg:TI (match_operand:TI 1 "general_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && ix86_unary_operator_ok (NEG, TImode, operands)" - "#") - -(define_split - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (neg:TI (match_operand:TI 1 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(parallel - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (neg:DI (match_dup 2)) (const_int 0))) - (set (match_dup 0) (neg:DI (match_dup 2)))]) - (parallel - [(set (match_dup 1) - (plus:DI (plus:DI (ltu:DI (reg:CC FLAGS_REG) (const_int 0)) - (match_dup 3)) - (const_int 0))) - (clobber (reg:CC FLAGS_REG))]) - (parallel - [(set (match_dup 1) - (neg:DI (match_dup 1))) - (clobber (reg:CC FLAGS_REG))])] - "split_ti (operands+1, 1, operands+2, operands+3); - split_ti (operands+0, 1, operands+0, operands+1);") - (define_expand "negdi2" [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") (neg:DI (match_operand:DI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "ix86_expand_unary_operator (NEG, DImode, operands); DONE;") (define_insn "*negdi2_1" [(set (match_operand:DI 0 "nonimmediate_operand" "=ro") (neg:DI (match_operand:DI 1 "general_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && ix86_unary_operator_ok (NEG, DImode, operands)" "#") @@ -9372,29 +9450,29 @@ (define_split [(set (match_operand:DI 0 "nonimmediate_operand" "") (neg:DI (match_operand:DI 1 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && reload_completed" [(parallel - [(set (reg:CCZ FLAGS_REG) + [(set (reg:CCZ 17) (compare:CCZ (neg:SI (match_dup 2)) (const_int 0))) (set (match_dup 0) (neg:SI (match_dup 2)))]) (parallel [(set (match_dup 1) - (plus:SI (plus:SI (ltu:SI (reg:CC FLAGS_REG) (const_int 0)) + (plus:SI (plus:SI (ltu:SI (reg:CC 17) (const_int 0)) (match_dup 3)) (const_int 0))) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (parallel [(set (match_dup 1) (neg:SI (match_dup 1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "split_di (operands+1, 1, operands+2, operands+3); split_di (operands+0, 1, operands+0, operands+1);") (define_insn "*negdi2_1_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") (neg:DI (match_operand:DI 1 "nonimmediate_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_unary_operator_ok (NEG, DImode, operands)" "neg{q}\t%0" [(set_attr "type" "negnot") @@ -9405,7 +9483,7 @@ ;; flag being the only useful item. (define_insn "*negdi2_cmpz_rex64" - [(set (reg:CCZ FLAGS_REG) + [(set (reg:CCZ 17) (compare:CCZ (neg:DI (match_operand:DI 1 "nonimmediate_operand" "0")) (const_int 0))) (set (match_operand:DI 0 "nonimmediate_operand" "=rm") @@ -9419,14 +9497,14 @@ (define_expand "negsi2" [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") (neg:SI (match_operand:SI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "ix86_expand_unary_operator (NEG, SImode, operands); DONE;") (define_insn "*negsi2_1" [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_unary_operator_ok (NEG, SImode, operands)" "neg{l}\t%0" [(set_attr "type" "negnot") @@ -9438,7 +9516,7 @@ (lshiftrt:DI (neg:DI (ashift:DI (match_operand:DI 1 "register_operand" "0") (const_int 32))) (const_int 32))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_unary_operator_ok (NEG, SImode, operands)" "neg{l}\t%k0" [(set_attr "type" "negnot") @@ -9449,7 +9527,7 @@ ;; flag being the only useful item. (define_insn "*negsi2_cmpz" - [(set (reg:CCZ FLAGS_REG) + [(set (reg:CCZ 17) (compare:CCZ (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")) (const_int 0))) (set (match_operand:SI 0 "nonimmediate_operand" "=rm") @@ -9460,7 +9538,7 @@ (set_attr "mode" "SI")]) (define_insn "*negsi2_cmpz_zext" - [(set (reg:CCZ FLAGS_REG) + [(set (reg:CCZ 17) (compare:CCZ (lshiftrt:DI (neg:DI (ashift:DI (match_operand:DI 1 "register_operand" "0") @@ -9479,21 +9557,21 @@ (define_expand "neghi2" [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "") (neg:HI (match_operand:HI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_HIMODE_MATH" "ix86_expand_unary_operator (NEG, HImode, operands); DONE;") (define_insn "*neghi2_1" [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_unary_operator_ok (NEG, HImode, operands)" "neg{w}\t%0" [(set_attr "type" "negnot") (set_attr "mode" "HI")]) (define_insn "*neghi2_cmpz" - [(set (reg:CCZ FLAGS_REG) + [(set (reg:CCZ 17) (compare:CCZ (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")) (const_int 0))) (set (match_operand:HI 0 "nonimmediate_operand" "=rm") @@ -9506,21 +9584,21 @@ (define_expand "negqi2" [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "") (neg:QI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "TARGET_QIMODE_MATH" "ix86_expand_unary_operator (NEG, QImode, operands); DONE;") (define_insn "*negqi2_1" [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_unary_operator_ok (NEG, QImode, operands)" "neg{b}\t%0" [(set_attr "type" "negnot") (set_attr "mode" "QI")]) (define_insn "*negqi2_cmpz" - [(set (reg:CCZ FLAGS_REG) + [(set (reg:CCZ 17) (compare:CCZ (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")) (const_int 0))) (set (match_operand:QI 0 "nonimmediate_operand" "=qm") @@ -9533,403 +9611,747 @@ ;; Changing of sign for FP values is doable using integer unit too. (define_expand "negsf2" - [(set (match_operand:SF 0 "nonimmediate_operand" "") - (neg:SF (match_operand:SF 1 "nonimmediate_operand" "")))] + [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] "TARGET_80387 || TARGET_SSE_MATH" - "ix86_expand_fp_absneg_operator (NEG, SFmode, operands); DONE;") + "if (TARGET_SSE_MATH) + { + /* In case operand is in memory, we will not use SSE. */ + if (memory_operand (operands[0], VOIDmode) + && rtx_equal_p (operands[0], operands[1])) + emit_insn (gen_negsf2_memory (operands[0], operands[1])); + else + { + /* Using SSE is tricky, since we need bitwise negation of -0 + in register. */ + rtx reg = gen_reg_rtx (SFmode); + rtx dest = operands[0]; + rtx imm = gen_lowpart (SFmode, gen_int_mode (0x80000000, SImode)); + + operands[1] = force_reg (SFmode, operands[1]); + operands[0] = force_reg (SFmode, operands[0]); + reg = force_reg (V4SFmode, + gen_rtx_CONST_VECTOR (V4SFmode, + gen_rtvec (4, imm, CONST0_RTX (SFmode), + CONST0_RTX (SFmode), + CONST0_RTX (SFmode)))); + emit_insn (gen_negsf2_ifs (operands[0], operands[1], reg)); + if (dest != operands[0]) + emit_move_insn (dest, operands[0]); + } + DONE; + } + ix86_expand_unary_operator (NEG, SFmode, operands); DONE;") -(define_expand "abssf2" - [(set (match_operand:SF 0 "nonimmediate_operand" "") - (abs:SF (match_operand:SF 1 "nonimmediate_operand" "")))] - "TARGET_80387 || TARGET_SSE_MATH" - "ix86_expand_fp_absneg_operator (ABS, SFmode, operands); DONE;") - -(define_insn "*absnegsf2_mixed" - [(set (match_operand:SF 0 "nonimmediate_operand" "=x ,x,f,rm") - (match_operator:SF 3 "absneg_operator" - [(match_operand:SF 1 "nonimmediate_operand" "0 ,x,0,0 ")])) - (use (match_operand:V4SF 2 "nonimmediate_operand" "xm ,0,X,X ")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_SSE_MATH && TARGET_MIX_SSE_I387 - && ix86_unary_operator_ok (GET_CODE (operands[3]), SFmode, operands)" +(define_insn "negsf2_memory" + [(set (match_operand:SF 0 "memory_operand" "=m") + (neg:SF (match_operand:SF 1 "memory_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (NEG, SFmode, operands)" "#") -(define_insn "*absnegsf2_sse" - [(set (match_operand:SF 0 "nonimmediate_operand" "=x,x,rm") - (match_operator:SF 3 "absneg_operator" - [(match_operand:SF 1 "nonimmediate_operand" "0 ,x,0")])) - (use (match_operand:V4SF 2 "nonimmediate_operand" "xm,0,X")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_SSE_MATH - && ix86_unary_operator_ok (GET_CODE (operands[3]), SFmode, operands)" +(define_insn "negsf2_ifs" + [(set (match_operand:SF 0 "nonimmediate_operand" "=x#fr,x#fr,f#xr,rm#xf") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" "0,x#fr,0,0"))) + (use (match_operand:V4SF 2 "nonimmediate_operand" "xm,0,xm*r,xm*r")) + (clobber (reg:CC 17))] + "TARGET_SSE + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" "#") -(define_insn "*absnegsf2_i387" - [(set (match_operand:SF 0 "nonimmediate_operand" "=f,rm") - (match_operator:SF 3 "absneg_operator" - [(match_operand:SF 1 "nonimmediate_operand" "0,0")])) - (use (match_operand 2 "" "")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_80387 && !TARGET_SSE_MATH - && ix86_unary_operator_ok (GET_CODE (operands[3]), SFmode, operands)" - "#") +(define_split + [(set (match_operand:SF 0 "memory_operand" "") + (neg:SF (match_operand:SF 1 "memory_operand" ""))) + (use (match_operand:SF 2 "" "")) + (clobber (reg:CC 17))] + "" + [(parallel [(set (match_dup 0) + (neg:SF (match_dup 1))) + (clobber (reg:CC 17))])]) -(define_expand "copysignsf3" - [(match_operand:SF 0 "register_operand" "") - (match_operand:SF 1 "nonmemory_operand" "") - (match_operand:SF 2 "register_operand" "")] - "TARGET_SSE_MATH" -{ - ix86_expand_copysign (operands); - DONE; -}) +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (neg:SF (match_operand:SF 1 "register_operand" ""))) + (use (match_operand:V4SF 2 "" "")) + (clobber (reg:CC 17))] + "reload_completed && !SSE_REG_P (operands[0])" + [(parallel [(set (match_dup 0) + (neg:SF (match_dup 1))) + (clobber (reg:CC 17))])]) -(define_insn_and_split "copysignsf3_const" - [(set (match_operand:SF 0 "register_operand" "=x") - (unspec:SF - [(match_operand:V4SF 1 "vector_move_operand" "xmC") - (match_operand:SF 2 "register_operand" "0") - (match_operand:V4SF 3 "nonimmediate_operand" "xm")] - UNSPEC_COPYSIGN))] - "TARGET_SSE_MATH" - "#" - "&& reload_completed" - [(const_int 0)] +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (neg:SF (match_operand:SF 1 "register_operand" ""))) + (use (match_operand:V4SF 2 "nonimmediate_operand" "")) + (clobber (reg:CC 17))] + "reload_completed && SSE_REG_P (operands[0])" + [(set (match_dup 0) + (xor:V4SF (match_dup 1) + (match_dup 2)))] { - ix86_split_copysign_const (operands); - DONE; + operands[0] = simplify_gen_subreg (V4SFmode, operands[0], SFmode, 0); + operands[1] = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0); + if (operands_match_p (operands[0], operands[2])) + { + rtx tmp; + tmp = operands[1]; + operands[1] = operands[2]; + operands[2] = tmp; + } }) -(define_insn "copysignsf3_var" - [(set (match_operand:SF 0 "register_operand" "=x, x, x, x,x") - (unspec:SF - [(match_operand:SF 2 "register_operand" " x, 0, 0, x,x") - (match_operand:SF 3 "register_operand" " 1, 1, x, 1,x") - (match_operand:V4SF 4 "nonimmediate_operand" " X,xm,xm, 0,0") - (match_operand:V4SF 5 "nonimmediate_operand" " 0,xm, 1,xm,1")] - UNSPEC_COPYSIGN)) - (clobber (match_scratch:V4SF 1 "=x, x, x, x,x"))] - "TARGET_SSE_MATH" + +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*negsf2_if" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f#r,rm#f") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_80387 + && ix86_unary_operator_ok (NEG, SFmode, operands)" "#") (define_split - [(set (match_operand:SF 0 "register_operand" "") - (unspec:SF - [(match_operand:SF 2 "register_operand" "") - (match_operand:SF 3 "register_operand" "") - (match_operand:V4SF 4 "" "") - (match_operand:V4SF 5 "" "")] - UNSPEC_COPYSIGN)) - (clobber (match_scratch:V4SF 1 ""))] - "TARGET_SSE_MATH && reload_completed" - [(const_int 0)] + [(set (match_operand:SF 0 "fp_register_operand" "") + (neg:SF (match_operand:SF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (neg:SF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:SF 0 "register_and_not_fp_reg_operand" "") + (neg:SF (match_operand:SF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed" + [(parallel [(set (match_dup 0) (xor:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[1] = gen_int_mode (0x80000000, SImode); + operands[0] = gen_lowpart (SImode, operands[0]);") + +(define_split + [(set (match_operand 0 "memory_operand" "") + (neg (match_operand 1 "memory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))" + [(parallel [(set (match_dup 0) (xor:QI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] { - ix86_split_copysign_var (operands); - DONE; + int size = GET_MODE_SIZE (GET_MODE (operands[1])); + + if (GET_MODE (operands[1]) == XFmode) + size = 10; + operands[0] = adjust_address (operands[0], QImode, size - 1); + operands[1] = gen_int_mode (0x80, QImode); }) (define_expand "negdf2" - [(set (match_operand:DF 0 "nonimmediate_operand" "") - (neg:DF (match_operand:DF 1 "nonimmediate_operand" "")))] + [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" - "ix86_expand_fp_absneg_operator (NEG, DFmode, operands); DONE;") + "if (TARGET_SSE2 && TARGET_SSE_MATH) + { + /* In case operand is in memory, we will not use SSE. */ + if (memory_operand (operands[0], VOIDmode) + && rtx_equal_p (operands[0], operands[1])) + emit_insn (gen_negdf2_memory (operands[0], operands[1])); + else + { + /* Using SSE is tricky, since we need bitwise negation of -0 + in register. */ + rtx reg; +#if HOST_BITS_PER_WIDE_INT >= 64 + rtx imm = gen_int_mode (((HOST_WIDE_INT)1) << 63, DImode); +#else + rtx imm = immed_double_const (0, 0x80000000, DImode); +#endif + rtx dest = operands[0]; + + operands[1] = force_reg (DFmode, operands[1]); + operands[0] = force_reg (DFmode, operands[0]); + imm = gen_lowpart (DFmode, imm); + reg = force_reg (V2DFmode, + gen_rtx_CONST_VECTOR (V2DFmode, + gen_rtvec (2, imm, CONST0_RTX (DFmode)))); + emit_insn (gen_negdf2_ifs (operands[0], operands[1], reg)); + if (dest != operands[0]) + emit_move_insn (dest, operands[0]); + } + DONE; + } + ix86_expand_unary_operator (NEG, DFmode, operands); DONE;") -(define_expand "absdf2" - [(set (match_operand:DF 0 "nonimmediate_operand" "") - (abs:DF (match_operand:DF 1 "nonimmediate_operand" "")))] - "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" - "ix86_expand_fp_absneg_operator (ABS, DFmode, operands); DONE;") - -(define_insn "*absnegdf2_mixed" - [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,Y,f,rm") - (match_operator:DF 3 "absneg_operator" - [(match_operand:DF 1 "nonimmediate_operand" "0 ,Y,0,0")])) - (use (match_operand:V2DF 2 "nonimmediate_operand" "Ym,0,X,X")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387 - && ix86_unary_operator_ok (GET_CODE (operands[3]), DFmode, operands)" +(define_insn "negdf2_memory" + [(set (match_operand:DF 0 "memory_operand" "=m") + (neg:DF (match_operand:DF 1 "memory_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (NEG, DFmode, operands)" "#") -(define_insn "*absnegdf2_sse" - [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,Y,rm") - (match_operator:DF 3 "absneg_operator" - [(match_operand:DF 1 "nonimmediate_operand" "0 ,Y,0 ")])) - (use (match_operand:V2DF 2 "nonimmediate_operand" "Ym,0,X ")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_SSE2 && TARGET_SSE_MATH - && ix86_unary_operator_ok (GET_CODE (operands[3]), DFmode, operands)" +(define_insn "negdf2_ifs" + [(set (match_operand:DF 0 "nonimmediate_operand" "=Y#fr,Y#fr,f#Yr,rm#Yf") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" "0,Y#fr,0,0"))) + (use (match_operand:V2DF 2 "nonimmediate_operand" "Ym,0,Ym*r,Ym*r")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_SSE2 + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" "#") -(define_insn "*absnegdf2_i387" - [(set (match_operand:DF 0 "nonimmediate_operand" "=f,rm") - (match_operator:DF 3 "absneg_operator" - [(match_operand:DF 1 "nonimmediate_operand" "0,0")])) - (use (match_operand 2 "" "")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_80387 && !(TARGET_SSE2 && TARGET_SSE_MATH) - && ix86_unary_operator_ok (GET_CODE (operands[3]), DFmode, operands)" +(define_insn "*negdf2_ifs_rex64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=Y#f,Y#f,fm#Y") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" "0,Y#fr,0"))) + (use (match_operand:V2DF 2 "nonimmediate_operand" "Ym,0,Ym*r")) + (clobber (reg:CC 17))] + "TARGET_64BIT && TARGET_SSE2 + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" "#") -(define_expand "copysigndf3" - [(match_operand:DF 0 "register_operand" "") - (match_operand:DF 1 "nonmemory_operand" "") - (match_operand:DF 2 "register_operand" "")] - "TARGET_SSE2 && TARGET_SSE_MATH" -{ - ix86_expand_copysign (operands); - DONE; -}) +(define_split + [(set (match_operand:DF 0 "memory_operand" "") + (neg:DF (match_operand:DF 1 "memory_operand" ""))) + (use (match_operand:V2DF 2 "" "")) + (clobber (reg:CC 17))] + "" + [(parallel [(set (match_dup 0) + (neg:DF (match_dup 1))) + (clobber (reg:CC 17))])]) -(define_insn_and_split "copysigndf3_const" - [(set (match_operand:DF 0 "register_operand" "=x") - (unspec:DF - [(match_operand:V2DF 1 "vector_move_operand" "xmC") - (match_operand:DF 2 "register_operand" "0") - (match_operand:V2DF 3 "nonimmediate_operand" "xm")] - UNSPEC_COPYSIGN))] - "TARGET_SSE2 && TARGET_SSE_MATH" - "#" - "&& reload_completed" - [(const_int 0)] -{ - ix86_split_copysign_const (operands); - DONE; -}) +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" ""))) + (use (match_operand:V2DF 2 "" "")) + (clobber (reg:CC 17))] + "reload_completed && !SSE_REG_P (operands[0]) + && (!TARGET_64BIT || FP_REG_P (operands[0]))" + [(parallel [(set (match_dup 0) + (neg:DF (match_dup 1))) + (clobber (reg:CC 17))])]) -(define_insn "copysigndf3_var" - [(set (match_operand:DF 0 "register_operand" "=x, x, x, x,x") - (unspec:DF - [(match_operand:DF 2 "register_operand" " x, 0, 0, x,x") - (match_operand:DF 3 "register_operand" " 1, 1, x, 1,x") - (match_operand:V2DF 4 "nonimmediate_operand" " X,xm,xm, 0,0") - (match_operand:V2DF 5 "nonimmediate_operand" " 0,xm, 1,xm,1")] - UNSPEC_COPYSIGN)) - (clobber (match_scratch:V2DF 1 "=x, x, x, x,x"))] - "TARGET_SSE2 && TARGET_SSE_MATH" - "#") +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" ""))) + (use (match_operand:V2DF 2 "" "")) + (clobber (reg:CC 17))] + "TARGET_64BIT && reload_completed && GENERAL_REG_P (operands[0])" + [(parallel [(set (match_dup 0) + (xor:DI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))])] + "operands[0] = gen_lowpart (DImode, operands[0]); + operands[1] = gen_lowpart (DImode, operands[1]); + operands[2] = gen_lowpart (DImode, operands[2]);") (define_split [(set (match_operand:DF 0 "register_operand" "") - (unspec:DF - [(match_operand:DF 2 "register_operand" "") - (match_operand:DF 3 "register_operand" "") - (match_operand:V2DF 4 "" "") - (match_operand:V2DF 5 "" "")] - UNSPEC_COPYSIGN)) - (clobber (match_scratch:V2DF 1 ""))] - "TARGET_SSE2 && TARGET_SSE_MATH && reload_completed" - [(const_int 0)] -{ - ix86_split_copysign_var (operands); - DONE; + (neg:DF (match_operand:DF 1 "register_operand" ""))) + (use (match_operand:V2DF 2 "nonimmediate_operand" "")) + (clobber (reg:CC 17))] + "reload_completed && SSE_REG_P (operands[0])" + [(set (match_dup 0) + (xor:V2DF (match_dup 1) + (match_dup 2)))] +{ + operands[0] = simplify_gen_subreg (V2DFmode, operands[0], DFmode, 0); + operands[1] = simplify_gen_subreg (V2DFmode, operands[1], DFmode, 0); + /* Avoid possible reformatting on the operands. */ + if (TARGET_SSE_PARTIAL_REGS && !optimize_size) + emit_insn (gen_sse2_unpcklpd (operands[0], operands[0], operands[0])); + if (operands_match_p (operands[0], operands[2])) + { + rtx tmp; + tmp = operands[1]; + operands[1] = operands[2]; + operands[2] = tmp; + } }) +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*negdf2_if" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f#r,rm#f") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_80387 + && ix86_unary_operator_ok (NEG, DFmode, operands)" + "#") + +;; FIXME: We should to allow integer registers here. Problem is that +;; we need another scratch register to get constant from. +;; Forcing constant to mem if no register available in peep2 should be +;; safe even for PIC mode, because of RIP relative addressing. +(define_insn "*negdf2_if_rex64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,mf") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && TARGET_80387 + && ix86_unary_operator_ok (NEG, DFmode, operands)" + "#") + +(define_split + [(set (match_operand:DF 0 "fp_register_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (neg:DF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:DF 0 "register_and_not_fp_reg_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_80387 && reload_completed" + [(parallel [(set (match_dup 3) (xor:SI (match_dup 3) (match_dup 4))) + (clobber (reg:CC 17))])] + "operands[4] = gen_int_mode (0x80000000, SImode); + split_di (operands+0, 1, operands+2, operands+3);") + (define_expand "negxf2" - [(set (match_operand:XF 0 "nonimmediate_operand" "") - (neg:XF (match_operand:XF 1 "nonimmediate_operand" "")))] + [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "") + (neg:XF (match_operand:XF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] "TARGET_80387" - "ix86_expand_fp_absneg_operator (NEG, XFmode, operands); DONE;") + "ix86_expand_unary_operator (NEG, XFmode, operands); DONE;") + +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*negxf2_if" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,rm#f") + (neg:XF (match_operand:XF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_80387 + && ix86_unary_operator_ok (NEG, XFmode, operands)" + "#") -(define_expand "absxf2" - [(set (match_operand:XF 0 "nonimmediate_operand" "") - (abs:XF (match_operand:XF 1 "nonimmediate_operand" "")))] +(define_split + [(set (match_operand:XF 0 "fp_register_operand" "") + (neg:XF (match_operand:XF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (neg:XF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:XF 0 "register_and_not_fp_reg_operand" "") + (neg:XF (match_operand:XF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed" + [(parallel [(set (match_dup 0) (xor:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[1] = GEN_INT (0x8000); + operands[0] = gen_rtx_REG (SImode, + true_regnum (operands[0]) + (TARGET_64BIT ? 1 : 2));") + +;; Conditionalize these after reload. If they matches before reload, we +;; lose the clobber and ability to use integer instructions. + +(define_insn "*negsf2_1" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "register_operand" "0")))] + "TARGET_80387 && reload_completed" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "SF") + (set_attr "ppro_uops" "few")]) + +(define_insn "*negdf2_1" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "register_operand" "0")))] + "TARGET_80387 && reload_completed" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "DF") + (set_attr "ppro_uops" "few")]) + +(define_insn "*negextendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (float_extend:DF + (match_operand:SF 1 "register_operand" "0"))))] "TARGET_80387" - "ix86_expand_fp_absneg_operator (ABS, XFmode, operands); DONE;") - -(define_insn "*absnegxf2_i387" - [(set (match_operand:XF 0 "nonimmediate_operand" "=f,?rm") - (match_operator:XF 3 "absneg_operator" - [(match_operand:XF 1 "nonimmediate_operand" "0,0")])) - (use (match_operand 2 "" "")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_80387 - && ix86_unary_operator_ok (GET_CODE (operands[3]), XFmode, operands)" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "DF") + (set_attr "ppro_uops" "few")]) + +(define_insn "*negxf2_1" + [(set (match_operand:XF 0 "register_operand" "=f") + (neg:XF (match_operand:XF 1 "register_operand" "0")))] + "TARGET_80387 && reload_completed" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF") + (set_attr "ppro_uops" "few")]) + +(define_insn "*negextenddfxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (neg:XF (float_extend:XF + (match_operand:DF 1 "register_operand" "0"))))] + "TARGET_80387" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF") + (set_attr "ppro_uops" "few")]) + +(define_insn "*negextendsfxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (neg:XF (float_extend:XF + (match_operand:SF 1 "register_operand" "0"))))] + "TARGET_80387" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF") + (set_attr "ppro_uops" "few")]) + +;; Absolute value instructions + +(define_expand "abssf2" + [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_80387 || TARGET_SSE_MATH" + "if (TARGET_SSE_MATH) + { + /* In case operand is in memory, we will not use SSE. */ + if (memory_operand (operands[0], VOIDmode) + && rtx_equal_p (operands[0], operands[1])) + emit_insn (gen_abssf2_memory (operands[0], operands[1])); + else + { + /* Using SSE is tricky, since we need bitwise negation of -0 + in register. */ + rtx reg = gen_reg_rtx (V4SFmode); + rtx dest = operands[0]; + rtx imm; + + operands[1] = force_reg (SFmode, operands[1]); + operands[0] = force_reg (SFmode, operands[0]); + imm = gen_lowpart (SFmode, gen_int_mode(~0x80000000, SImode)); + reg = force_reg (V4SFmode, + gen_rtx_CONST_VECTOR (V4SFmode, + gen_rtvec (4, imm, CONST0_RTX (SFmode), + CONST0_RTX (SFmode), + CONST0_RTX (SFmode)))); + emit_insn (gen_abssf2_ifs (operands[0], operands[1], reg)); + if (dest != operands[0]) + emit_move_insn (dest, operands[0]); + } + DONE; + } + ix86_expand_unary_operator (ABS, SFmode, operands); DONE;") + +(define_insn "abssf2_memory" + [(set (match_operand:SF 0 "memory_operand" "=m") + (abs:SF (match_operand:SF 1 "memory_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (ABS, SFmode, operands)" "#") -;; Splitters for fp abs and neg. +(define_insn "abssf2_ifs" + [(set (match_operand:SF 0 "nonimmediate_operand" "=x#fr,x#fr,f#xr,rm#xf") + (abs:SF (match_operand:SF 1 "nonimmediate_operand" "0,x#fr,0,0"))) + (use (match_operand:V4SF 2 "nonimmediate_operand" "xm,0,xm*r,xm*r")) + (clobber (reg:CC 17))] + "TARGET_SSE + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" + "#") (define_split - [(set (match_operand 0 "fp_register_operand" "") - (match_operator 1 "absneg_operator" [(match_dup 0)])) - (use (match_operand 2 "" "")) - (clobber (reg:CC FLAGS_REG))] - "reload_completed" - [(set (match_dup 0) (match_op_dup 1 [(match_dup 0)]))]) + [(set (match_operand:SF 0 "memory_operand" "") + (abs:SF (match_operand:SF 1 "memory_operand" ""))) + (use (match_operand:V4SF 2 "" "")) + (clobber (reg:CC 17))] + "" + [(parallel [(set (match_dup 0) + (abs:SF (match_dup 1))) + (clobber (reg:CC 17))])]) (define_split - [(set (match_operand 0 "register_operand" "") - (match_operator 3 "absneg_operator" - [(match_operand 1 "register_operand" "")])) - (use (match_operand 2 "nonimmediate_operand" "")) - (clobber (reg:CC FLAGS_REG))] + [(set (match_operand:SF 0 "register_operand" "") + (abs:SF (match_operand:SF 1 "register_operand" ""))) + (use (match_operand:V4SF 2 "" "")) + (clobber (reg:CC 17))] + "reload_completed && !SSE_REG_P (operands[0])" + [(parallel [(set (match_dup 0) + (abs:SF (match_dup 1))) + (clobber (reg:CC 17))])]) + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (abs:SF (match_operand:SF 1 "register_operand" ""))) + (use (match_operand:V4SF 2 "nonimmediate_operand" "")) + (clobber (reg:CC 17))] "reload_completed && SSE_REG_P (operands[0])" - [(set (match_dup 0) (match_dup 3))] + [(set (match_dup 0) + (and:V4SF (match_dup 1) + (match_dup 2)))] { - enum machine_mode mode = GET_MODE (operands[0]); - enum machine_mode vmode = GET_MODE (operands[2]); - rtx tmp; - - operands[0] = simplify_gen_subreg (vmode, operands[0], mode, 0); - operands[1] = simplify_gen_subreg (vmode, operands[1], mode, 0); + operands[0] = simplify_gen_subreg (V4SFmode, operands[0], SFmode, 0); + operands[1] = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0); if (operands_match_p (operands[0], operands[2])) { + rtx tmp; tmp = operands[1]; operands[1] = operands[2]; operands[2] = tmp; } - if (GET_CODE (operands[3]) == ABS) - tmp = gen_rtx_AND (vmode, operands[1], operands[2]); - else - tmp = gen_rtx_XOR (vmode, operands[1], operands[2]); - operands[3] = tmp; }) +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*abssf2_if" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f#r,rm#f") + (abs:SF (match_operand:SF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_80387 && ix86_unary_operator_ok (ABS, SFmode, operands)" + "#") + (define_split - [(set (match_operand:SF 0 "register_operand" "") - (match_operator:SF 1 "absneg_operator" [(match_dup 0)])) - (use (match_operand:V4SF 2 "" "")) - (clobber (reg:CC FLAGS_REG))] - "reload_completed" - [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (reg:CC FLAGS_REG))])] -{ - rtx tmp; - operands[0] = gen_lowpart (SImode, operands[0]); - if (GET_CODE (operands[1]) == ABS) - { - tmp = gen_int_mode (0x7fffffff, SImode); - tmp = gen_rtx_AND (SImode, operands[0], tmp); - } - else - { - tmp = gen_int_mode (0x80000000, SImode); - tmp = gen_rtx_XOR (SImode, operands[0], tmp); - } - operands[1] = tmp; -}) + [(set (match_operand:SF 0 "fp_register_operand" "") + (abs:SF (match_operand:SF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (abs:SF (match_dup 1)))] + "") (define_split - [(set (match_operand:DF 0 "register_operand" "") - (match_operator:DF 1 "absneg_operator" [(match_dup 0)])) - (use (match_operand 2 "" "")) - (clobber (reg:CC FLAGS_REG))] - "reload_completed" - [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (reg:CC FLAGS_REG))])] + [(set (match_operand:SF 0 "register_and_not_fp_reg_operand" "") + (abs:SF (match_operand:SF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed" + [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[1] = gen_int_mode (~0x80000000, SImode); + operands[0] = gen_lowpart (SImode, operands[0]);") + +(define_split + [(set (match_operand 0 "memory_operand" "") + (abs (match_operand 1 "memory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))" + [(parallel [(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] { - rtx tmp; - if (TARGET_64BIT) - { - tmp = gen_lowpart (DImode, operands[0]); - tmp = gen_rtx_ZERO_EXTRACT (DImode, tmp, const1_rtx, GEN_INT (63)); - operands[0] = tmp; + int size = GET_MODE_SIZE (GET_MODE (operands[1])); - if (GET_CODE (operands[1]) == ABS) - tmp = const0_rtx; - else - tmp = gen_rtx_NOT (DImode, tmp); - } - else - { - operands[0] = gen_highpart (SImode, operands[0]); - if (GET_CODE (operands[1]) == ABS) - { - tmp = gen_int_mode (0x7fffffff, SImode); - tmp = gen_rtx_AND (SImode, operands[0], tmp); - } - else + if (GET_MODE (operands[1]) == XFmode) + size = 10; + operands[0] = adjust_address (operands[0], QImode, size - 1); + operands[1] = gen_int_mode (~0x80, QImode); +}) + +(define_expand "absdf2" + [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" + "if (TARGET_SSE2 && TARGET_SSE_MATH) + { + /* In case operand is in memory, we will not use SSE. */ + if (memory_operand (operands[0], VOIDmode) + && rtx_equal_p (operands[0], operands[1])) + emit_insn (gen_absdf2_memory (operands[0], operands[1])); + else { - tmp = gen_int_mode (0x80000000, SImode); - tmp = gen_rtx_XOR (SImode, operands[0], tmp); + /* Using SSE is tricky, since we need bitwise negation of -0 + in register. */ + rtx reg = gen_reg_rtx (V2DFmode); +#if HOST_BITS_PER_WIDE_INT >= 64 + rtx imm = gen_int_mode (~(((HOST_WIDE_INT)1) << 63), DImode); +#else + rtx imm = immed_double_const (~0, ~0x80000000, DImode); +#endif + rtx dest = operands[0]; + + operands[1] = force_reg (DFmode, operands[1]); + operands[0] = force_reg (DFmode, operands[0]); + + /* Produce LONG_DOUBLE with the proper immediate argument. */ + imm = gen_lowpart (DFmode, imm); + reg = force_reg (V2DFmode, + gen_rtx_CONST_VECTOR (V2DFmode, + gen_rtvec (2, imm, CONST0_RTX (DFmode)))); + emit_insn (gen_absdf2_ifs (operands[0], operands[1], reg)); + if (dest != operands[0]) + emit_move_insn (dest, operands[0]); } - } - operands[1] = tmp; -}) + DONE; + } + ix86_expand_unary_operator (ABS, DFmode, operands); DONE;") + +(define_insn "absdf2_memory" + [(set (match_operand:DF 0 "memory_operand" "=m") + (abs:DF (match_operand:DF 1 "memory_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (ABS, DFmode, operands)" + "#") + +(define_insn "absdf2_ifs" + [(set (match_operand:DF 0 "nonimmediate_operand" "=Y#fr,Y#fr,mf#Yr,mr#Yf") + (abs:DF (match_operand:DF 1 "nonimmediate_operand" "0,Y#fr,0,0"))) + (use (match_operand:V2DF 2 "nonimmediate_operand" "Ym,0,Ym*r,Ym*r")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_SSE2 + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" + "#") + +(define_insn "*absdf2_ifs_rex64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=Y#fr,Y#fr,mf#Yr") + (abs:DF (match_operand:DF 1 "nonimmediate_operand" "0,Y#fr,0"))) + (use (match_operand:V2DF 2 "nonimmediate_operand" "Ym,0,Ym*r")) + (clobber (reg:CC 17))] + "TARGET_64BIT && TARGET_SSE2 + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" + "#") (define_split - [(set (match_operand:XF 0 "register_operand" "") - (match_operator:XF 1 "absneg_operator" [(match_dup 0)])) - (use (match_operand 2 "" "")) - (clobber (reg:CC FLAGS_REG))] - "reload_completed" - [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (reg:CC FLAGS_REG))])] -{ - rtx tmp; - operands[0] = gen_rtx_REG (SImode, - true_regnum (operands[0]) - + (TARGET_64BIT ? 1 : 2)); - if (GET_CODE (operands[1]) == ABS) - { - tmp = GEN_INT (0x7fff); - tmp = gen_rtx_AND (SImode, operands[0], tmp); - } - else - { - tmp = GEN_INT (0x8000); - tmp = gen_rtx_XOR (SImode, operands[0], tmp); - } - operands[1] = tmp; -}) + [(set (match_operand:DF 0 "memory_operand" "") + (abs:DF (match_operand:DF 1 "memory_operand" ""))) + (use (match_operand:V2DF 2 "" "")) + (clobber (reg:CC 17))] + "" + [(parallel [(set (match_dup 0) + (abs:DF (match_dup 1))) + (clobber (reg:CC 17))])]) (define_split - [(set (match_operand 0 "memory_operand" "") - (match_operator 1 "absneg_operator" [(match_dup 0)])) - (use (match_operand 2 "" "")) - (clobber (reg:CC FLAGS_REG))] - "reload_completed" - [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (reg:CC FLAGS_REG))])] -{ - enum machine_mode mode = GET_MODE (operands[0]); - int size = mode == XFmode ? 10 : GET_MODE_SIZE (mode); - rtx tmp; + [(set (match_operand:DF 0 "register_operand" "") + (abs:DF (match_operand:DF 1 "register_operand" ""))) + (use (match_operand:V2DF 2 "" "")) + (clobber (reg:CC 17))] + "reload_completed && !SSE_REG_P (operands[0])" + [(parallel [(set (match_dup 0) + (abs:DF (match_dup 1))) + (clobber (reg:CC 17))])]) - operands[0] = adjust_address (operands[0], QImode, size - 1); - if (GET_CODE (operands[1]) == ABS) - { - tmp = gen_int_mode (0x7f, QImode); - tmp = gen_rtx_AND (QImode, operands[0], tmp); - } - else +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (abs:DF (match_operand:DF 1 "register_operand" ""))) + (use (match_operand:V2DF 2 "nonimmediate_operand" "")) + (clobber (reg:CC 17))] + "reload_completed && SSE_REG_P (operands[0])" + [(set (match_dup 0) + (and:V2DF (match_dup 1) + (match_dup 2)))] +{ + operands[0] = simplify_gen_subreg (V2DFmode, operands[0], DFmode, 0); + operands[1] = simplify_gen_subreg (V2DFmode, operands[1], DFmode, 0); + /* Avoid possible reformatting on the operands. */ + if (TARGET_SSE_PARTIAL_REGS && !optimize_size) + emit_insn (gen_sse2_unpcklpd (operands[0], operands[0], operands[0])); + if (operands_match_p (operands[0], operands[2])) { - tmp = gen_int_mode (0x80, QImode); - tmp = gen_rtx_XOR (QImode, operands[0], tmp); + rtx tmp; + tmp = operands[1]; + operands[1] = operands[2]; + operands[2] = tmp; } - operands[1] = tmp; }) -;; Conditionalize these after reload. If they match before reload, we -;; lose the clobber and ability to use integer instructions. -(define_insn "*negsf2_1" - [(set (match_operand:SF 0 "register_operand" "=f") - (neg:SF (match_operand:SF 1 "register_operand" "0")))] - "TARGET_80387 && (reload_completed || !TARGET_SSE_MATH)" - "fchs" - [(set_attr "type" "fsgn") - (set_attr "mode" "SF")]) +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*absdf2_if" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f#r,rm#f") + (abs:DF (match_operand:DF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_80387 + && ix86_unary_operator_ok (ABS, DFmode, operands)" + "#") -(define_insn "*negdf2_1" - [(set (match_operand:DF 0 "register_operand" "=f") - (neg:DF (match_operand:DF 1 "register_operand" "0")))] - "TARGET_80387 && (reload_completed || !(TARGET_SSE2 && TARGET_SSE_MATH))" - "fchs" - [(set_attr "type" "fsgn") - (set_attr "mode" "DF")]) +;; FIXME: We should to allow integer registers here. Problem is that +;; we need another scratch register to get constant from. +;; Forcing constant to mem if no register available in peep2 should be +;; safe even for PIC mode, because of RIP relative addressing. +(define_insn "*absdf2_if_rex64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,mf") + (abs:DF (match_operand:DF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && TARGET_80387 + && ix86_unary_operator_ok (ABS, DFmode, operands)" + "#") -(define_insn "*negxf2_1" - [(set (match_operand:XF 0 "register_operand" "=f") - (neg:XF (match_operand:XF 1 "register_operand" "0")))] +(define_split + [(set (match_operand:DF 0 "fp_register_operand" "") + (abs:DF (match_operand:DF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (abs:DF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:DF 0 "register_and_not_fp_reg_operand" "") + (abs:DF (match_operand:DF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_80387 && reload_completed" + [(parallel [(set (match_dup 3) (and:SI (match_dup 3) (match_dup 4))) + (clobber (reg:CC 17))])] + "operands[4] = gen_int_mode (~0x80000000, SImode); + split_di (operands+0, 1, operands+2, operands+3);") + +(define_expand "absxf2" + [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "") + (neg:XF (match_operand:XF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] "TARGET_80387" - "fchs" - [(set_attr "type" "fsgn") - (set_attr "mode" "XF")]) + "ix86_expand_unary_operator (ABS, XFmode, operands); DONE;") + +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*absxf2_if" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,rm#f") + (abs:XF (match_operand:XF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_80387 + && ix86_unary_operator_ok (ABS, XFmode, operands)" + "#") + +(define_split + [(set (match_operand:XF 0 "fp_register_operand" "") + (abs:XF (match_operand:XF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (abs:XF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:XF 0 "register_and_not_fp_reg_operand" "") + (abs:XF (match_operand:XF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed" + [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[1] = GEN_INT (~0x8000); + operands[0] = gen_rtx_REG (SImode, + true_regnum (operands[0]) + (TARGET_64BIT ? 1 : 2));") (define_insn "*abssf2_1" [(set (match_operand:SF 0 "register_operand" "=f") (abs:SF (match_operand:SF 1 "register_operand" "0")))] - "TARGET_80387 && (reload_completed || !TARGET_SSE_MATH)" + "TARGET_80387 && reload_completed" "fabs" [(set_attr "type" "fsgn") (set_attr "mode" "SF")]) @@ -9937,51 +10359,24 @@ (define_insn "*absdf2_1" [(set (match_operand:DF 0 "register_operand" "=f") (abs:DF (match_operand:DF 1 "register_operand" "0")))] - "TARGET_80387 && (reload_completed || !(TARGET_SSE2 && TARGET_SSE_MATH))" - "fabs" - [(set_attr "type" "fsgn") - (set_attr "mode" "DF")]) - -(define_insn "*absxf2_1" - [(set (match_operand:XF 0 "register_operand" "=f") - (abs:XF (match_operand:XF 1 "register_operand" "0")))] - "TARGET_80387" + "TARGET_80387 && reload_completed" "fabs" [(set_attr "type" "fsgn") (set_attr "mode" "DF")]) -(define_insn "*negextendsfdf2" +(define_insn "*absextendsfdf2" [(set (match_operand:DF 0 "register_operand" "=f") - (neg:DF (float_extend:DF + (abs:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))] - "TARGET_80387 && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387)" - "fchs" - [(set_attr "type" "fsgn") - (set_attr "mode" "DF")]) - -(define_insn "*negextenddfxf2" - [(set (match_operand:XF 0 "register_operand" "=f") - (neg:XF (float_extend:XF - (match_operand:DF 1 "register_operand" "0"))))] "TARGET_80387" - "fchs" + "fabs" [(set_attr "type" "fsgn") - (set_attr "mode" "XF")]) + (set_attr "mode" "DF")]) -(define_insn "*negextendsfxf2" +(define_insn "*absxf2_1" [(set (match_operand:XF 0 "register_operand" "=f") - (neg:XF (float_extend:XF - (match_operand:SF 1 "register_operand" "0"))))] - "TARGET_80387" - "fchs" - [(set_attr "type" "fsgn") - (set_attr "mode" "XF")]) - -(define_insn "*absextendsfdf2" - [(set (match_operand:DF 0 "register_operand" "=f") - (abs:DF (float_extend:DF - (match_operand:SF 1 "register_operand" "0"))))] - "TARGET_80387 && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387)" + (abs:XF (match_operand:XF 1 "register_operand" "0")))] + "TARGET_80387 && reload_completed" "fabs" [(set_attr "type" "fsgn") (set_attr "mode" "DF")]) @@ -10021,7 +10416,7 @@ (set_attr "mode" "DI")]) (define_insn "*one_cmpldi2_2_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (not:DI (match_operand:DI 1 "nonimmediate_operand" "0")) (const_int 0))) (set (match_operand:DI 0 "nonimmediate_operand" "=rm") @@ -10072,7 +10467,7 @@ (set_attr "mode" "SI")]) (define_insn "*one_cmplsi2_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")) (const_int 0))) (set (match_operand:SI 0 "nonimmediate_operand" "=rm") @@ -10100,7 +10495,7 @@ ;; ??? Currently never generated - xor is used instead. (define_insn "*one_cmplsi2_2_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (not:SI (match_operand:SI 1 "register_operand" "0")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") @@ -10141,7 +10536,7 @@ (set_attr "mode" "HI")]) (define_insn "*one_cmplhi2_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (not:HI (match_operand:HI 1 "nonimmediate_operand" "0")) (const_int 0))) (set (match_operand:HI 0 "nonimmediate_operand" "=rm") @@ -10185,7 +10580,7 @@ (set_attr "mode" "QI,SI")]) (define_insn "*one_cmplqi2_2" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (not:QI (match_operand:QI 1 "nonimmediate_operand" "0")) (const_int 0))) (set (match_operand:QI 0 "nonimmediate_operand" "=qm") @@ -10235,116 +10630,42 @@ ;; shift pair, instead using moves and sign extension for counts greater ;; than 31. -(define_expand "ashlti3" - [(parallel [(set (match_operand:TI 0 "register_operand" "") - (ashift:TI (match_operand:TI 1 "register_operand" "") +(define_expand "ashldi3" + [(parallel [(set (match_operand:DI 0 "shiftdi_operand" "") + (ashift:DI (match_operand:DI 1 "shiftdi_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" + (clobber (reg:CC 17))])] + "" { - if (! immediate_operand (operands[2], QImode)) + if (!TARGET_64BIT && TARGET_CMOVE && ! immediate_operand (operands[2], QImode)) { - emit_insn (gen_ashlti3_1 (operands[0], operands[1], operands[2])); + emit_insn (gen_ashldi3_1 (operands[0], operands[1], operands[2])); DONE; } - ix86_expand_binary_operator (ASHIFT, TImode, operands); + ix86_expand_binary_operator (ASHIFT, DImode, operands); DONE; }) -(define_insn "ashlti3_1" - [(set (match_operand:TI 0 "register_operand" "=r") - (ashift:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:QI 2 "register_operand" "c"))) - (clobber (match_scratch:DI 3 "=&r")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -(define_insn "*ashlti3_2" - [(set (match_operand:TI 0 "register_operand" "=r") - (ashift:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:QI 2 "immediate_operand" "O"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -(define_split - [(set (match_operand:TI 0 "register_operand" "") - (ashift:TI (match_operand:TI 1 "nonmemory_operand" "") - (match_operand:QI 2 "register_operand" ""))) - (clobber (match_scratch:DI 3 "")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(const_int 0)] - "ix86_split_ashl (operands, operands[3], TImode); DONE;") - -(define_split - [(set (match_operand:TI 0 "register_operand" "") - (ashift:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "immediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(const_int 0)] - "ix86_split_ashl (operands, NULL_RTX, TImode); DONE;") - -(define_insn "x86_64_shld" - [(set (match_operand:DI 0 "nonimmediate_operand" "+r*m,r*m") - (ior:DI (ashift:DI (match_dup 0) - (match_operand:QI 2 "nonmemory_operand" "J,c")) - (lshiftrt:DI (match_operand:DI 1 "register_operand" "r,r") - (minus:QI (const_int 64) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "@ - shld{q}\t{%2, %1, %0|%0, %1, %2} - shld{q}\t{%s2%1, %0|%0, %1, %2}" - [(set_attr "type" "ishift") - (set_attr "prefix_0f" "1") - (set_attr "mode" "DI") - (set_attr "athlon_decode" "vector")]) - -(define_expand "x86_64_shift_adj" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (and:QI (match_operand:QI 2 "register_operand" "") - (const_int 64)) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "") - (if_then_else:DI (ne (reg:CCZ FLAGS_REG) (const_int 0)) - (match_operand:DI 1 "register_operand" "") - (match_dup 0))) - (set (match_dup 1) - (if_then_else:DI (ne (reg:CCZ FLAGS_REG) (const_int 0)) - (match_operand:DI 3 "register_operand" "r") - (match_dup 1)))] - "TARGET_64BIT" - "") - -(define_expand "ashldi3" - [(set (match_operand:DI 0 "shiftdi_operand" "") - (ashift:DI (match_operand:DI 1 "ashldi_input_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "ix86_expand_binary_operator (ASHIFT, DImode, operands); DONE;") - (define_insn "*ashldi3_1_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") - (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0,l") + (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0,r") (match_operand:QI 2 "nonmemory_operand" "cJ,M"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ASHIFT, DImode, operands)" { switch (get_attr_type (insn)) { case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (operands[2] != const1_rtx) + abort (); + if (!rtx_equal_p (operands[0], operands[1])) + abort (); return "add{q}\t{%0, %0|%0, %0}"; case TYPE_LEA: - gcc_assert (GET_CODE (operands[2]) == CONST_INT); - gcc_assert ((unsigned HOST_WIDE_INT) INTVAL (operands[2]) <= 3); + if (GET_CODE (operands[2]) != CONST_INT + || (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 3) + abort (); operands[1] = gen_rtx_MULT (DImode, operands[1], GEN_INT (1 << INTVAL (operands[2]))); return "lea{q}\t{%a1, %0|%0, %a1}"; @@ -10352,7 +10673,8 @@ default: if (REG_P (operands[2])) return "sal{q}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) return "sal{q}\t%0"; else @@ -10374,9 +10696,9 @@ ;; Convert lea to the lea pattern to avoid flags dependency. (define_split [(set (match_operand:DI 0 "register_operand" "") - (ashift:DI (match_operand:DI 1 "index_register_operand" "") + (ashift:DI (match_operand:DI 1 "register_operand" "") (match_operand:QI 2 "immediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && reload_completed && true_regnum (operands[0]) != true_regnum (operands[1])" [(set (match_dup 0) @@ -10388,7 +10710,7 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashldi3_cmp_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "immediate_operand" "e")) @@ -10396,23 +10718,20 @@ (set (match_operand:DI 0 "nonimmediate_operand" "=rm") (ashift:DI (match_dup 1) (match_dup 2)))] "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, DImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0])))))" + && ix86_binary_operator_ok (ASHIFT, DImode, operands)" { switch (get_attr_type (insn)) { case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); + if (operands[2] != const1_rtx) + abort (); return "add{q}\t{%0, %0|%0, %0}"; default: if (REG_P (operands[2])) return "sal{q}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) return "sal{q}\t%0"; else @@ -10429,79 +10748,43 @@ (const_string "ishift"))) (set_attr "mode" "DI")]) -(define_insn "*ashldi3_cconly_rex64" - [(set (reg FLAGS_REG) - (compare - (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "immediate_operand" "e")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, DImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || TARGET_DOUBLE_WITH_ADD)))" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{q}\t{%0, %0|%0, %0}"; - - default: - if (REG_P (operands[2])) - return "sal{q}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_size)) - return "sal{q}\t%0"; - else - return "sal{q}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set_attr "mode" "DI")]) +(define_insn "ashldi3_1" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "Jc"))) + (clobber (match_scratch:SI 3 "=&r")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE" + "#" + [(set_attr "type" "multi")]) -(define_insn "*ashldi3_1" - [(set (match_operand:DI 0 "register_operand" "=&r,r") - (ashift:DI (match_operand:DI 1 "reg_or_pm1_operand" "n,0") - (match_operand:QI 2 "nonmemory_operand" "Jc,Jc"))) - (clobber (reg:CC FLAGS_REG))] +(define_insn "*ashldi3_2" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "Jc"))) + (clobber (reg:CC 17))] "!TARGET_64BIT" "#" [(set_attr "type" "multi")]) -;; By default we don't ask for a scratch register, because when DImode -;; values are manipulated, registers are already at a premium. But if -;; we have one handy, we won't turn it away. -(define_peephole2 - [(match_scratch:SI 3 "r") - (parallel [(set (match_operand:DI 0 "register_operand" "") - (ashift:DI (match_operand:DI 1 "nonmemory_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (match_dup 3)] - "!TARGET_64BIT && TARGET_CMOVE" +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ashift:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (match_scratch:SI 3 "")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE && reload_completed" [(const_int 0)] - "ix86_split_ashl (operands, operands[3], DImode); DONE;") + "ix86_split_ashldi (operands, operands[3]); DONE;") (define_split [(set (match_operand:DI 0 "register_operand" "") - (ashift:DI (match_operand:DI 1 "nonmemory_operand" "") + (ashift:DI (match_operand:DI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? flow2_completed : reload_completed)" + (clobber (reg:CC 17))] + "!TARGET_64BIT && reload_completed" [(const_int 0)] - "ix86_split_ashl (operands, NULL_RTX, DImode); DONE;") + "ix86_split_ashldi (operands, NULL_RTX); DONE;") (define_insn "x86_shld_1" [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m,r*m") @@ -10509,7 +10792,7 @@ (match_operand:QI 2 "nonmemory_operand" "I,c")) (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") (minus:QI (const_int 32) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "@ shld{l}\t{%2, %1, %0|%0, %1, %2} @@ -10518,19 +10801,20 @@ (set_attr "prefix_0f" "1") (set_attr "mode" "SI") (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector")]) + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) (define_expand "x86_shift_adj_1" - [(set (reg:CCZ FLAGS_REG) + [(set (reg:CCZ 17) (compare:CCZ (and:QI (match_operand:QI 2 "register_operand" "") (const_int 32)) (const_int 0))) (set (match_operand:SI 0 "register_operand" "") - (if_then_else:SI (ne (reg:CCZ FLAGS_REG) (const_int 0)) + (if_then_else:SI (ne (reg:CCZ 17) (const_int 0)) (match_operand:SI 1 "register_operand" "") (match_dup 0))) (set (match_dup 1) - (if_then_else:SI (ne (reg:CCZ FLAGS_REG) (const_int 0)) + (if_then_else:SI (ne (reg:CCZ 17) (const_int 0)) (match_operand:SI 3 "register_operand" "r") (match_dup 1)))] "TARGET_CMOVE" @@ -10556,7 +10840,7 @@ JUMP_LABEL (tmp) = label; emit_move_insn (operands[0], operands[1]); - ix86_expand_clear (operands[1]); + emit_move_insn (operands[1], const0_rtx); emit_label (label); LABEL_NUSES (label) = 1; @@ -10568,22 +10852,24 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "") (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "ix86_expand_binary_operator (ASHIFT, SImode, operands); DONE;") (define_insn "*ashlsi3_1" [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") - (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,l") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,r") (match_operand:QI 2 "nonmemory_operand" "cI,M"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ASHIFT, SImode, operands)" { switch (get_attr_type (insn)) { case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (operands[2] != const1_rtx) + abort (); + if (!rtx_equal_p (operands[0], operands[1])) + abort (); return "add{l}\t{%0, %0|%0, %0}"; case TYPE_LEA: @@ -10592,7 +10878,8 @@ default: if (REG_P (operands[2])) return "sal{l}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) return "sal{l}\t%0"; else @@ -10616,21 +10903,15 @@ [(set (match_operand 0 "register_operand" "") (ashift (match_operand 1 "index_register_operand" "") (match_operand:QI 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed - && true_regnum (operands[0]) != true_regnum (operands[1]) - && GET_MODE_SIZE (GET_MODE (operands[0])) <= 4" + && true_regnum (operands[0]) != true_regnum (operands[1])" [(const_int 0)] { rtx pat; - enum machine_mode mode = GET_MODE (operands[0]); - - if (GET_MODE_SIZE (mode) < 4) - operands[0] = gen_lowpart (SImode, operands[0]); - if (mode != Pmode) - operands[1] = gen_lowpart (Pmode, operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (Pmode, operands[1]); operands[2] = gen_int_mode (1 << INTVAL (operands[2]), Pmode); - pat = gen_rtx_MULT (Pmode, operands[1], operands[2]); if (Pmode != SImode) pat = gen_rtx_SUBREG (SImode, pat, 0); @@ -10643,13 +10924,13 @@ [(set (match_operand 0 "register_operand" "") (ashift (match_operand 1 "register_operand" "") (match_operand:QI 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "reload_completed && true_regnum (operands[0]) != true_regnum (operands[1])" [(const_int 0)] { rtx pat, clob; - emit_move_insn (operands[0], operands[1]); + emit_move_insn (operands[1], operands[0]); pat = gen_rtx_SET (VOIDmode, operands[0], gen_rtx_ASHIFT (GET_MODE (operands[0]), operands[0], operands[2])); @@ -10660,15 +10941,16 @@ (define_insn "*ashlsi3_1_zext" [(set (match_operand:DI 0 "register_operand" "=r,r") - (zero_extend:DI (ashift:SI (match_operand:SI 1 "register_operand" "0,l") + (zero_extend:DI (ashift:SI (match_operand:SI 1 "register_operand" "0,r") (match_operand:QI 2 "nonmemory_operand" "cI,M")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ASHIFT, SImode, operands)" { switch (get_attr_type (insn)) { case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); + if (operands[2] != const1_rtx) + abort (); return "add{l}\t{%k0, %k0|%k0, %k0}"; case TYPE_LEA: @@ -10677,7 +10959,8 @@ default: if (REG_P (operands[2])) return "sal{l}\t{%b2, %k0|%k0, %b2}"; - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) return "sal{l}\t%k0"; else @@ -10700,7 +10983,7 @@ [(set (match_operand:DI 0 "register_operand" "") (zero_extend:DI (ashift (match_operand 1 "register_operand" "") (match_operand:QI 2 "const_int_operand" "")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && reload_completed && true_regnum (operands[0]) != true_regnum (operands[1])" [(set (match_dup 0) (zero_extend:DI @@ -10715,72 +10998,28 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashlsi3_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:SI 0 "nonimmediate_operand" "=rm") (ashift:SI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, SImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0])))))" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{l}\t{%0, %0|%0, %0}"; - - default: - if (REG_P (operands[2])) - return "sal{l}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_size)) - return "sal{l}\t%0"; - else - return "sal{l}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set_attr "mode" "SI")]) - -(define_insn "*ashlsi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, SImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || TARGET_DOUBLE_WITH_ADD)))" + && ix86_binary_operator_ok (ASHIFT, SImode, operands)" { switch (get_attr_type (insn)) { case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); + if (operands[2] != const1_rtx) + abort (); return "add{l}\t{%0, %0|%0, %0}"; default: if (REG_P (operands[2])) return "sal{l}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) return "sal{l}\t%0"; else @@ -10798,31 +11037,28 @@ (set_attr "mode" "SI")]) (define_insn "*ashlsi3_cmp_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashift:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (ashift:SI (match_dup 1) (match_dup 2))))] "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, SImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || TARGET_DOUBLE_WITH_ADD)))" + && ix86_binary_operator_ok (ASHIFT, SImode, operands)" { switch (get_attr_type (insn)) { case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); + if (operands[2] != const1_rtx) + abort (); return "add{l}\t{%k0, %k0|%k0, %k0}"; default: if (REG_P (operands[2])) return "sal{l}\t{%b2, %k0|%k0, %b2}"; - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) return "sal{l}\t%k0"; else @@ -10842,15 +11078,15 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "") (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_HIMODE_MATH" "ix86_expand_binary_operator (ASHIFT, HImode, operands); DONE;") (define_insn "*ashlhi3_1_lea" [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") - (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0,l") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0,r") (match_operand:QI 2 "nonmemory_operand" "cI,M"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_PARTIAL_REG_STALL && ix86_binary_operator_ok (ASHIFT, HImode, operands)" { @@ -10859,13 +11095,15 @@ case TYPE_LEA: return "#"; case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); + if (operands[2] != const1_rtx) + abort (); return "add{w}\t{%0, %0|%0, %0}"; default: if (REG_P (operands[2])) return "sal{w}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) return "sal{w}\t%0"; else @@ -10888,20 +11126,22 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "nonmemory_operand" "cI"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_PARTIAL_REG_STALL && ix86_binary_operator_ok (ASHIFT, HImode, operands)" { switch (get_attr_type (insn)) { case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); + if (operands[2] != const1_rtx) + abort (); return "add{w}\t{%0, %0|%0, %0}"; default: if (REG_P (operands[2])) return "sal{w}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) return "sal{w}\t%0"; else @@ -10922,72 +11162,28 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashlhi3_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:HI 0 "nonimmediate_operand" "=rm") (ashift:HI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0])))))" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{w}\t{%0, %0|%0, %0}"; - - default: - if (REG_P (operands[2])) - return "sal{w}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_size)) - return "sal{w}\t%0"; - else - return "sal{w}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set_attr "mode" "HI")]) - -(define_insn "*ashlhi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || TARGET_DOUBLE_WITH_ADD)))" + && ix86_binary_operator_ok (ASHIFT, HImode, operands)" { switch (get_attr_type (insn)) { case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); + if (operands[2] != const1_rtx) + abort (); return "add{w}\t{%0, %0|%0, %0}"; default: if (REG_P (operands[2])) return "sal{w}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) return "sal{w}\t%0"; else @@ -11008,7 +11204,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "") (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH" "ix86_expand_binary_operator (ASHIFT, QImode, operands); DONE;") @@ -11016,9 +11212,9 @@ (define_insn "*ashlqi3_1_lea" [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r,r") - (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,l") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,r") (match_operand:QI 2 "nonmemory_operand" "cI,cI,M"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_PARTIAL_REG_STALL && ix86_binary_operator_ok (ASHIFT, QImode, operands)" { @@ -11027,7 +11223,8 @@ case TYPE_LEA: return "#"; case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); + if (operands[2] != const1_rtx) + abort (); if (REG_P (operands[1]) && !ANY_QI_REG_P (operands[1])) return "add{l}\t{%k0, %k0|%k0, %k0}"; else @@ -11041,7 +11238,8 @@ else return "sal{b}\t{%b2, %0|%0, %b2}"; } - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) { if (get_attr_mode (insn) == MODE_SI) @@ -11074,14 +11272,15 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r") (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "cI,cI"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_PARTIAL_REG_STALL && ix86_binary_operator_ok (ASHIFT, QImode, operands)" { switch (get_attr_type (insn)) { case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); + if (operands[2] != const1_rtx) + abort (); if (REG_P (operands[1]) && !ANY_QI_REG_P (operands[1])) return "add{l}\t{%k0, %k0|%k0, %k0}"; else @@ -11095,7 +11294,8 @@ else return "sal{b}\t{%b2, %0|%0, %b2}"; } - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) { if (get_attr_mode (insn) == MODE_SI) @@ -11126,72 +11326,28 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashlqi3_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:QI 0 "nonimmediate_operand" "=qm") (ashift:QI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, QImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0])))))" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{b}\t{%0, %0|%0, %0}"; - - default: - if (REG_P (operands[2])) - return "sal{b}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_size)) - return "sal{b}\t%0"; - else - return "sal{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set_attr "mode" "QI")]) - -(define_insn "*ashlqi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, QImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || TARGET_DOUBLE_WITH_ADD)))" + && ix86_binary_operator_ok (ASHIFT, QImode, operands)" { switch (get_attr_type (insn)) { case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); + if (operands[2] != const1_rtx) + abort (); return "add{b}\t{%0, %0|%0, %0}"; default: if (REG_P (operands[2])) return "sal{b}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 && (TARGET_SHIFT1 || optimize_size)) return "sal{b}\t%0"; else @@ -11210,90 +11366,28 @@ ;; See comment above `ashldi3' about how this works. -(define_expand "ashrti3" - [(parallel [(set (match_operand:TI 0 "register_operand" "") - (ashiftrt:TI (match_operand:TI 1 "register_operand" "") +(define_expand "ashrdi3" + [(parallel [(set (match_operand:DI 0 "shiftdi_operand" "") + (ashiftrt:DI (match_operand:DI 1 "shiftdi_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" + (clobber (reg:CC 17))])] + "" { - if (! immediate_operand (operands[2], QImode)) + if (!TARGET_64BIT && TARGET_CMOVE && ! immediate_operand (operands[2], QImode)) { - emit_insn (gen_ashrti3_1 (operands[0], operands[1], operands[2])); + emit_insn (gen_ashrdi3_1 (operands[0], operands[1], operands[2])); DONE; } - ix86_expand_binary_operator (ASHIFTRT, TImode, operands); + ix86_expand_binary_operator (ASHIFTRT, DImode, operands); DONE; }) -(define_insn "ashrti3_1" - [(set (match_operand:TI 0 "register_operand" "=r") - (ashiftrt:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:QI 2 "register_operand" "c"))) - (clobber (match_scratch:DI 3 "=&r")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -(define_insn "*ashrti3_2" - [(set (match_operand:TI 0 "register_operand" "=r") - (ashiftrt:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:QI 2 "immediate_operand" "O"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -(define_split - [(set (match_operand:TI 0 "register_operand" "") - (ashiftrt:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "register_operand" ""))) - (clobber (match_scratch:DI 3 "")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(const_int 0)] - "ix86_split_ashr (operands, operands[3], TImode); DONE;") - -(define_split - [(set (match_operand:TI 0 "register_operand" "") - (ashiftrt:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "immediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(const_int 0)] - "ix86_split_ashr (operands, NULL_RTX, TImode); DONE;") - -(define_insn "x86_64_shrd" - [(set (match_operand:DI 0 "nonimmediate_operand" "+r*m,r*m") - (ior:DI (ashiftrt:DI (match_dup 0) - (match_operand:QI 2 "nonmemory_operand" "J,c")) - (ashift:DI (match_operand:DI 1 "register_operand" "r,r") - (minus:QI (const_int 64) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "@ - shrd{q}\t{%2, %1, %0|%0, %1, %2} - shrd{q}\t{%s2%1, %0|%0, %1, %2}" - [(set_attr "type" "ishift") - (set_attr "prefix_0f" "1") - (set_attr "mode" "DI") - (set_attr "athlon_decode" "vector")]) - -(define_expand "ashrdi3" - [(set (match_operand:DI 0 "shiftdi_operand" "") - (ashiftrt:DI (match_operand:DI 1 "shiftdi_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "ix86_expand_binary_operator (ASHIFTRT, DImode, operands); DONE;") - -(define_insn "*ashrdi3_63_rex64" +(define_insn "ashrdi3_63_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=*d,rm") (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "*a,0") (match_operand:DI 2 "const_int_operand" "i,i"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && INTVAL (operands[2]) == 63 - && (TARGET_USE_CLTD || optimize_size) + (clobber (reg:CC 17))] + "TARGET_64BIT && INTVAL (operands[2]) == 63 && (TARGET_USE_CLTD || optimize_size) && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" "@ {cqto|cqo} @@ -11308,7 +11402,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ASHIFTRT, DImode, operands) && (TARGET_SHIFT1 || optimize_size)" "sar{q}\t%0" @@ -11322,7 +11416,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "J,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" "@ sar{q}\t{%2, %0|%0, %2} @@ -11334,7 +11428,7 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashrdi3_one_bit_cmp_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" "")) @@ -11351,25 +11445,11 @@ (const_string "2") (const_string "*")))]) -(define_insn "*ashrdi3_one_bit_cconly_rex64" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && (TARGET_SHIFT1 || optimize_size) - && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" - "sar{q}\t%0" - [(set_attr "type" "ishift") - (set_attr "length" "2")]) - ;; This pattern can't accept a variable shift count, since shifts by ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashrdi3_cmp_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const_int_operand" "n")) @@ -11377,60 +11457,49 @@ (set (match_operand:DI 0 "nonimmediate_operand" "=rm") (ashiftrt:DI (match_dup 1) (match_dup 2)))] "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, DImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" + && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" "sar{q}\t{%2, %0|%0, %2}" [(set_attr "type" "ishift") (set_attr "mode" "DI")]) -(define_insn "*ashrdi3_cconly_rex64" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_int_operand" "n")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, DImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" - "sar{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "DI")]) -(define_insn "*ashrdi3_1" +(define_insn "ashrdi3_1" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "Jc"))) + (clobber (match_scratch:SI 3 "=&r")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE" + "#" + [(set_attr "type" "multi")]) + +(define_insn "*ashrdi3_2" [(set (match_operand:DI 0 "register_operand" "=r") (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") (match_operand:QI 2 "nonmemory_operand" "Jc"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT" "#" [(set_attr "type" "multi")]) -;; By default we don't ask for a scratch register, because when DImode -;; values are manipulated, registers are already at a premium. But if -;; we have one handy, we won't turn it away. -(define_peephole2 - [(match_scratch:SI 3 "r") - (parallel [(set (match_operand:DI 0 "register_operand" "") - (ashiftrt:DI (match_operand:DI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (match_dup 3)] - "!TARGET_64BIT && TARGET_CMOVE" +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (match_scratch:SI 3 "")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE && reload_completed" [(const_int 0)] - "ix86_split_ashr (operands, operands[3], DImode); DONE;") + "ix86_split_ashrdi (operands, operands[3]); DONE;") (define_split [(set (match_operand:DI 0 "register_operand" "") (ashiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? flow2_completed : reload_completed)" + (clobber (reg:CC 17))] + "!TARGET_64BIT && reload_completed" [(const_int 0)] - "ix86_split_ashr (operands, NULL_RTX, DImode); DONE;") + "ix86_split_ashrdi (operands, NULL_RTX); DONE;") (define_insn "x86_shrd_1" [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m,r*m") @@ -11438,7 +11507,7 @@ (match_operand:QI 2 "nonmemory_operand" "I,c")) (ashift:SI (match_operand:SI 1 "register_operand" "r,r") (minus:QI (const_int 32) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "@ shrd{l}\t{%2, %1, %0|%0, %1, %2} @@ -11446,6 +11515,7 @@ [(set_attr "type" "ishift") (set_attr "prefix_0f" "1") (set_attr "pent_pair" "np") + (set_attr "ppro_uops" "few") (set_attr "mode" "SI")]) (define_expand "x86_shift_adj_3" @@ -11480,7 +11550,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=*d,rm") (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "*a,0") (match_operand:SI 2 "const_int_operand" "i,i"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "INTVAL (operands[2]) == 31 && (TARGET_USE_CLTD || optimize_size) && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" "@ @@ -11496,7 +11566,7 @@ [(set (match_operand:DI 0 "register_operand" "=*d,r") (zero_extend:DI (ashiftrt:SI (match_operand:SI 1 "register_operand" "*a,0") (match_operand:SI 2 "const_int_operand" "i,i")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && (TARGET_USE_CLTD || optimize_size) && INTVAL (operands[2]) == 31 && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" @@ -11513,7 +11583,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "") (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "ix86_expand_binary_operator (ASHIFTRT, SImode, operands); DONE;") @@ -11521,7 +11591,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ASHIFTRT, SImode, operands) && (TARGET_SHIFT1 || optimize_size)" "sar{l}\t%0" @@ -11535,7 +11605,7 @@ [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "const1_operand" "")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ASHIFTRT, SImode, operands) && (TARGET_SHIFT1 || optimize_size)" "sar{l}\t%k0" @@ -11546,7 +11616,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" "@ sar{l}\t{%2, %0|%0, %2} @@ -11558,7 +11628,7 @@ [(set (match_operand:DI 0 "register_operand" "=r,r") (zero_extend:DI (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" "@ sar{l}\t{%2, %k0|%k0, %2} @@ -11570,7 +11640,7 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashrsi3_one_bit_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" "")) @@ -11587,22 +11657,8 @@ (const_string "2") (const_string "*")))]) -(define_insn "*ashrsi3_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && (TARGET_SHIFT1 || optimize_size) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "sar{l}\t%0" - [(set_attr "type" "ishift") - (set_attr "length" "2")]) - (define_insn "*ashrsi3_one_bit_cmp_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "const1_operand" "")) @@ -11620,48 +11676,29 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashrsi3_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:SI 0 "nonimmediate_operand" "=rm") (ashiftrt:SI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" - "sar{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) - -(define_insn "*ashrsi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" + && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" "sar{l}\t{%2, %0|%0, %2}" [(set_attr "type" "ishift") (set_attr "mode" "SI")]) (define_insn "*ashrsi3_cmp_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (ashiftrt:SI (match_dup 1) (match_dup 2))))] "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" + && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" "sar{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "ishift") (set_attr "mode" "SI")]) @@ -11670,7 +11707,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "") (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_HIMODE_MATH" "ix86_expand_binary_operator (ASHIFTRT, HImode, operands); DONE;") @@ -11678,7 +11715,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ASHIFTRT, HImode, operands) && (TARGET_SHIFT1 || optimize_size)" "sar{w}\t%0" @@ -11692,7 +11729,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" "@ sar{w}\t{%2, %0|%0, %2} @@ -11704,7 +11741,7 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashrhi3_one_bit_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" "")) @@ -11721,50 +11758,19 @@ (const_string "2") (const_string "*")))]) -(define_insn "*ashrhi3_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && (TARGET_SHIFT1 || optimize_size) - && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" - "sar{w}\t%0" - [(set_attr "type" "ishift") - (set_attr "length" "2")]) - ;; This pattern can't accept a variable shift count, since shifts by ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashrhi3_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:HI 0 "nonimmediate_operand" "=rm") (ashiftrt:HI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" - "sar{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "HI")]) - -(define_insn "*ashrhi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" + && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" "sar{w}\t{%2, %0|%0, %2}" [(set_attr "type" "ishift") (set_attr "mode" "HI")]) @@ -11773,7 +11779,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "") (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH" "ix86_expand_binary_operator (ASHIFTRT, QImode, operands); DONE;") @@ -11781,7 +11787,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ASHIFTRT, QImode, operands) && (TARGET_SHIFT1 || optimize_size)" "sar{b}\t%0" @@ -11795,7 +11801,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) (ashiftrt:QI (match_dup 0) (match_operand:QI 1 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ASHIFTRT, QImode, operands) && (! TARGET_PARTIAL_REG_STALL || optimize_size) && (TARGET_SHIFT1 || optimize_size)" @@ -11810,7 +11816,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" "@ sar{b}\t{%2, %0|%0, %2} @@ -11822,7 +11828,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,qm")) (ashiftrt:QI (match_dup 0) (match_operand:QI 1 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "@ @@ -11835,7 +11841,7 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashrqi3_one_bit_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" "I")) @@ -11852,125 +11858,48 @@ (const_string "2") (const_string "*")))]) -(define_insn "*ashrqi3_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "I")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "ix86_match_ccmode (insn, CCGOCmode) - && (TARGET_SHIFT1 || optimize_size) - && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" - "sar{b}\t%0" - [(set_attr "type" "ishift") - (set_attr "length" "2")]) - ;; This pattern can't accept a variable shift count, since shifts by ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*ashrqi3_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:QI 0 "nonimmediate_operand" "=qm") (ashiftrt:QI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, QImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" - "sar{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "QI")]) - -(define_insn "*ashrqi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, QImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" + && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" "sar{b}\t{%2, %0|%0, %2}" [(set_attr "type" "ishift") (set_attr "mode" "QI")]) - ;; Logical shift instructions ;; See comment above `ashldi3' about how this works. -(define_expand "lshrti3" - [(parallel [(set (match_operand:TI 0 "register_operand" "") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "") +(define_expand "lshrdi3" + [(parallel [(set (match_operand:DI 0 "shiftdi_operand" "") + (lshiftrt:DI (match_operand:DI 1 "shiftdi_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" + (clobber (reg:CC 17))])] + "" { - if (! immediate_operand (operands[2], QImode)) + if (!TARGET_64BIT && TARGET_CMOVE && ! immediate_operand (operands[2], QImode)) { - emit_insn (gen_lshrti3_1 (operands[0], operands[1], operands[2])); + emit_insn (gen_lshrdi3_1 (operands[0], operands[1], operands[2])); DONE; } - ix86_expand_binary_operator (LSHIFTRT, TImode, operands); + ix86_expand_binary_operator (LSHIFTRT, DImode, operands); DONE; }) -(define_insn "lshrti3_1" - [(set (match_operand:TI 0 "register_operand" "=r") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:QI 2 "register_operand" "c"))) - (clobber (match_scratch:DI 3 "=&r")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -(define_insn "*lshrti3_2" - [(set (match_operand:TI 0 "register_operand" "=r") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:QI 2 "immediate_operand" "O"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -(define_split - [(set (match_operand:TI 0 "register_operand" "") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "register_operand" ""))) - (clobber (match_scratch:DI 3 "")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(const_int 0)] - "ix86_split_lshr (operands, operands[3], TImode); DONE;") - -(define_split - [(set (match_operand:TI 0 "register_operand" "") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "immediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(const_int 0)] - "ix86_split_lshr (operands, NULL_RTX, TImode); DONE;") - -(define_expand "lshrdi3" - [(set (match_operand:DI 0 "shiftdi_operand" "") - (lshiftrt:DI (match_operand:DI 1 "shiftdi_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "ix86_expand_binary_operator (LSHIFTRT, DImode, operands); DONE;") - (define_insn "*lshrdi3_1_one_bit_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) && (TARGET_SHIFT1 || optimize_size)" "shr{q}\t%0" @@ -11984,7 +11913,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "J,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" "@ shr{q}\t{%2, %0|%0, %2} @@ -11996,7 +11925,7 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*lshrdi3_cmp_one_bit_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" "")) @@ -12013,25 +11942,11 @@ (const_string "2") (const_string "*")))]) -(define_insn "*lshrdi3_cconly_one_bit_rex64" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && (TARGET_SHIFT1 || optimize_size) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{q}\t%0" - [(set_attr "type" "ishift") - (set_attr "length" "2")]) - ;; This pattern can't accept a variable shift count, since shifts by ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*lshrdi3_cmp_rex64" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const_int_operand" "e")) @@ -12039,66 +11954,54 @@ (set (match_operand:DI 0 "nonimmediate_operand" "=rm") (lshiftrt:DI (match_dup 1) (match_dup 2)))] "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" "shr{q}\t{%2, %0|%0, %2}" [(set_attr "type" "ishift") (set_attr "mode" "DI")]) -(define_insn "*lshrdi3_cconly_rex64" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_int_operand" "e")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" - "shr{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "DI")]) +(define_insn "lshrdi3_1" + [(set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "Jc"))) + (clobber (match_scratch:SI 3 "=&r")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE" + "#" + [(set_attr "type" "multi")]) -(define_insn "*lshrdi3_1" +(define_insn "*lshrdi3_2" [(set (match_operand:DI 0 "register_operand" "=r") (lshiftrt:DI (match_operand:DI 1 "register_operand" "0") (match_operand:QI 2 "nonmemory_operand" "Jc"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT" "#" [(set_attr "type" "multi")]) -;; By default we don't ask for a scratch register, because when DImode -;; values are manipulated, registers are already at a premium. But if -;; we have one handy, we won't turn it away. -(define_peephole2 - [(match_scratch:SI 3 "r") - (parallel [(set (match_operand:DI 0 "register_operand" "") - (lshiftrt:DI (match_operand:DI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (match_dup 3)] - "!TARGET_64BIT && TARGET_CMOVE" +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (match_scratch:SI 3 "")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE && reload_completed" [(const_int 0)] - "ix86_split_lshr (operands, operands[3], DImode); DONE;") + "ix86_split_lshrdi (operands, operands[3]); DONE;") (define_split [(set (match_operand:DI 0 "register_operand" "") (lshiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? flow2_completed : reload_completed)" + (clobber (reg:CC 17))] + "!TARGET_64BIT && reload_completed" [(const_int 0)] - "ix86_split_lshr (operands, NULL_RTX, DImode); DONE;") + "ix86_split_lshrdi (operands, NULL_RTX); DONE;") (define_expand "lshrsi3" [(set (match_operand:SI 0 "nonimmediate_operand" "") (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "ix86_expand_binary_operator (LSHIFTRT, SImode, operands); DONE;") @@ -12106,7 +12009,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (LSHIFTRT, HImode, operands) && (TARGET_SHIFT1 || optimize_size)" "shr{l}\t%0" @@ -12120,7 +12023,7 @@ [(set (match_operand:DI 0 "register_operand" "=r") (lshiftrt:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "0")) (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) && (TARGET_SHIFT1 || optimize_size)" "shr{l}\t%k0" @@ -12131,7 +12034,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" "@ shr{l}\t{%2, %0|%0, %2} @@ -12144,7 +12047,7 @@ (zero_extend:DI (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" "@ shr{l}\t{%2, %k0|%k0, %2} @@ -12156,7 +12059,7 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*lshrsi3_one_bit_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" "")) @@ -12173,22 +12076,8 @@ (const_string "2") (const_string "*")))]) -(define_insn "*lshrsi3_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && (TARGET_SHIFT1 || optimize_size) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{l}\t%0" - [(set_attr "type" "ishift") - (set_attr "length" "2")]) - (define_insn "*lshrsi3_cmp_one_bit_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "const1_operand" "")) @@ -12206,48 +12095,29 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*lshrsi3_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:SI 0 "nonimmediate_operand" "=rm") (lshiftrt:SI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" - "shr{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) - -(define_insn "*lshrsi3_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" "shr{l}\t{%2, %0|%0, %2}" [(set_attr "type" "ishift") (set_attr "mode" "SI")]) (define_insn "*lshrsi3_cmp_zext" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") (lshiftrt:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))] "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" "shr{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "ishift") (set_attr "mode" "SI")]) @@ -12256,7 +12126,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "") (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_HIMODE_MATH" "ix86_expand_binary_operator (LSHIFTRT, HImode, operands); DONE;") @@ -12264,7 +12134,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (LSHIFTRT, HImode, operands) && (TARGET_SHIFT1 || optimize_size)" "shr{w}\t%0" @@ -12278,7 +12148,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" "@ shr{w}\t{%2, %0|%0, %2} @@ -12290,7 +12160,7 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*lshrhi3_one_bit_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" "")) @@ -12307,50 +12177,19 @@ (const_string "2") (const_string "*")))]) -(define_insn "*lshrhi3_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && (TARGET_SHIFT1 || optimize_size) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{w}\t%0" - [(set_attr "type" "ishift") - (set_attr "length" "2")]) - ;; This pattern can't accept a variable shift count, since shifts by ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*lshrhi3_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:HI 0 "nonimmediate_operand" "=rm") (lshiftrt:HI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" - "shr{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "HI")]) - -(define_insn "*lshrhi3_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" "shr{w}\t{%2, %0|%0, %2}" [(set_attr "type" "ishift") (set_attr "mode" "HI")]) @@ -12359,7 +12198,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "") (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH" "ix86_expand_binary_operator (LSHIFTRT, QImode, operands); DONE;") @@ -12367,7 +12206,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (LSHIFTRT, QImode, operands) && (TARGET_SHIFT1 || optimize_size)" "shr{b}\t%0" @@ -12381,7 +12220,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) (lshiftrt:QI (match_dup 0) (match_operand:QI 1 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (TARGET_SHIFT1 || optimize_size)" "shr{b}\t%0" @@ -12395,7 +12234,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" "@ shr{b}\t{%2, %0|%0, %2} @@ -12407,7 +12246,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,qm")) (lshiftrt:QI (match_dup 0) (match_operand:QI 1 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "@ @@ -12420,7 +12259,7 @@ ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*lshrqi2_one_bit_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" "")) @@ -12437,50 +12276,19 @@ (const_string "2") (const_string "*")))]) -(define_insn "*lshrqi2_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "ix86_match_ccmode (insn, CCGOCmode) - && (TARGET_SHIFT1 || optimize_size) - && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" - "shr{b}\t%0" - [(set_attr "type" "ishift") - (set_attr "length" "2")]) - ;; This pattern can't accept a variable shift count, since shifts by ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. (define_insn "*lshrqi2_cmp" - [(set (reg FLAGS_REG) + [(set (reg 17) (compare (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_int_1_31_operand" "I")) (const_int 0))) (set (match_operand:QI 0 "nonimmediate_operand" "=qm") (lshiftrt:QI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, QImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" - "shr{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "QI")]) - -(define_insn "*lshrqi2_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, QImode, operands) - && (optimize_size - || !TARGET_PARTIAL_FLAG_REG_STALL)" + && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" "shr{b}\t{%2, %0|%0, %2}" [(set_attr "type" "ishift") (set_attr "mode" "QI")]) @@ -12488,54 +12296,18 @@ ;; Rotate instructions (define_expand "rotldi3" - [(set (match_operand:DI 0 "shiftdi_operand" "") - (rotate:DI (match_operand:DI 1 "shiftdi_operand" "") + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "" -{ - if (TARGET_64BIT) - { - ix86_expand_binary_operator (ROTATE, DImode, operands); - DONE; - } - if (!const_1_to_31_operand (operands[2], VOIDmode)) - FAIL; - emit_insn (gen_ix86_rotldi3 (operands[0], operands[1], operands[2])); - DONE; -}) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "ix86_expand_binary_operator (ROTATE, DImode, operands); DONE;") -;; Implement rotation using two double-precision shift instructions -;; and a scratch register. -(define_insn_and_split "ix86_rotldi3" - [(set (match_operand:DI 0 "register_operand" "=r") - (rotate:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I"))) - (clobber (reg:CC FLAGS_REG)) - (clobber (match_scratch:SI 3 "=&r"))] - "!TARGET_64BIT" - "" - "&& reload_completed" - [(set (match_dup 3) (match_dup 4)) - (parallel - [(set (match_dup 4) - (ior:SI (ashift:SI (match_dup 4) (match_dup 2)) - (lshiftrt:SI (match_dup 5) - (minus:QI (const_int 32) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))]) - (parallel - [(set (match_dup 5) - (ior:SI (ashift:SI (match_dup 5) (match_dup 2)) - (lshiftrt:SI (match_dup 3) - (minus:QI (const_int 32) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))])] - "split_di (operands, 1, operands + 4, operands + 5);") - (define_insn "*rotlsi3_1_one_bit_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ROTATE, DImode, operands) && (TARGET_SHIFT1 || optimize_size)" "rol{q}\t%0" @@ -12549,7 +12321,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "e,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ROTATE, DImode, operands)" "@ rol{q}\t{%2, %0|%0, %2} @@ -12561,7 +12333,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "") (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "ix86_expand_binary_operator (ROTATE, SImode, operands); DONE;") @@ -12569,7 +12341,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATE, SImode, operands) && (TARGET_SHIFT1 || optimize_size)" "rol{l}\t%0" @@ -12584,7 +12356,7 @@ (zero_extend:DI (rotate:SI (match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "const1_operand" "")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ROTATE, SImode, operands) && (TARGET_SHIFT1 || optimize_size)" "rol{l}\t%k0" @@ -12595,7 +12367,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATE, SImode, operands)" "@ rol{l}\t{%2, %0|%0, %2} @@ -12608,7 +12380,7 @@ (zero_extend:DI (rotate:SI (match_operand:SI 1 "register_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ROTATE, SImode, operands)" "@ rol{l}\t{%2, %k0|%k0, %2} @@ -12620,7 +12392,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "") (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_HIMODE_MATH" "ix86_expand_binary_operator (ROTATE, HImode, operands); DONE;") @@ -12628,7 +12400,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATE, HImode, operands) && (TARGET_SHIFT1 || optimize_size)" "rol{w}\t%0" @@ -12642,7 +12414,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATE, HImode, operands)" "@ rol{w}\t{%2, %0|%0, %2} @@ -12654,7 +12426,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "") (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH" "ix86_expand_binary_operator (ROTATE, QImode, operands); DONE;") @@ -12662,7 +12434,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) (rotate:QI (match_dup 0) (match_operand:QI 1 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (TARGET_SHIFT1 || optimize_size)" "rol{b}\t%0" @@ -12676,7 +12448,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATE, QImode, operands) && (TARGET_SHIFT1 || optimize_size)" "rol{b}\t%0" @@ -12690,7 +12462,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,qm")) (rotate:QI (match_dup 0) (match_operand:QI 1 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "@ @@ -12703,7 +12475,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATE, QImode, operands)" "@ rol{b}\t{%2, %0|%0, %2} @@ -12712,54 +12484,18 @@ (set_attr "mode" "QI")]) (define_expand "rotrdi3" - [(set (match_operand:DI 0 "shiftdi_operand" "") - (rotate:DI (match_operand:DI 1 "shiftdi_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "" -{ - if (TARGET_64BIT) - { - ix86_expand_binary_operator (ROTATERT, DImode, operands); - DONE; - } - if (!const_1_to_31_operand (operands[2], VOIDmode)) - FAIL; - emit_insn (gen_ix86_rotrdi3 (operands[0], operands[1], operands[2])); - DONE; -}) - -;; Implement rotation using two double-precision shift instructions -;; and a scratch register. -(define_insn_and_split "ix86_rotrdi3" - [(set (match_operand:DI 0 "register_operand" "=r") - (rotatert:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I"))) - (clobber (reg:CC FLAGS_REG)) - (clobber (match_scratch:SI 3 "=&r"))] - "!TARGET_64BIT" - "" - "&& reload_completed" - [(set (match_dup 3) (match_dup 4)) - (parallel - [(set (match_dup 4) - (ior:SI (ashiftrt:SI (match_dup 4) (match_dup 2)) - (ashift:SI (match_dup 5) - (minus:QI (const_int 32) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))]) - (parallel - [(set (match_dup 5) - (ior:SI (ashiftrt:SI (match_dup 5) (match_dup 2)) - (ashift:SI (match_dup 3) - (minus:QI (const_int 32) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))])] - "split_di (operands, 1, operands + 4, operands + 5);") + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "ix86_expand_binary_operator (ROTATERT, DImode, operands); DONE;") (define_insn "*rotrdi3_1_one_bit_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ROTATERT, DImode, operands) && (TARGET_SHIFT1 || optimize_size)" "ror{q}\t%0" @@ -12773,7 +12509,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "J,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ROTATERT, DImode, operands)" "@ ror{q}\t{%2, %0|%0, %2} @@ -12785,7 +12521,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "") (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "ix86_expand_binary_operator (ROTATERT, SImode, operands); DONE;") @@ -12793,7 +12529,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATERT, SImode, operands) && (TARGET_SHIFT1 || optimize_size)" "ror{l}\t%0" @@ -12808,7 +12544,7 @@ (zero_extend:DI (rotatert:SI (match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "const1_operand" "")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ROTATERT, SImode, operands) && (TARGET_SHIFT1 || optimize_size)" "ror{l}\t%k0" @@ -12822,7 +12558,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATERT, SImode, operands)" "@ ror{l}\t{%2, %0|%0, %2} @@ -12835,7 +12571,7 @@ (zero_extend:DI (rotatert:SI (match_operand:SI 1 "register_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && ix86_binary_operator_ok (ROTATERT, SImode, operands)" "@ ror{l}\t{%2, %k0|%k0, %2} @@ -12847,7 +12583,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "") (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_HIMODE_MATH" "ix86_expand_binary_operator (ROTATERT, HImode, operands); DONE;") @@ -12855,7 +12591,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATERT, HImode, operands) && (TARGET_SHIFT1 || optimize_size)" "ror{w}\t%0" @@ -12869,7 +12605,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATERT, HImode, operands)" "@ ror{w}\t{%2, %0|%0, %2} @@ -12881,7 +12617,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "") (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_QIMODE_MATH" "ix86_expand_binary_operator (ROTATERT, QImode, operands); DONE;") @@ -12889,7 +12625,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATERT, QImode, operands) && (TARGET_SHIFT1 || optimize_size)" "ror{b}\t%0" @@ -12903,7 +12639,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) (rotatert:QI (match_dup 0) (match_operand:QI 1 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (TARGET_SHIFT1 || optimize_size)" "ror{b}\t%0" @@ -12917,7 +12653,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "ix86_binary_operator_ok (ROTATERT, QImode, operands)" "@ ror{b}\t{%2, %0|%0, %2} @@ -12929,7 +12665,7 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,qm")) (rotatert:QI (match_dup 0) (match_operand:QI 1 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "(! TARGET_PARTIAL_REG_STALL || optimize_size) && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" "@ @@ -12943,8 +12679,8 @@ (define_expand "extv" [(set (match_operand:SI 0 "register_operand" "") (sign_extract:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "const8_operand" "") - (match_operand:SI 3 "const8_operand" "")))] + (match_operand:SI 2 "immediate_operand" "") + (match_operand:SI 3 "immediate_operand" "")))] "" { /* Handle extractions from %ah et al. */ @@ -12953,15 +12689,15 @@ /* From mips.md: extract_bit_field doesn't verify that our source matches the predicate, so check it again here. */ - if (! ext_register_operand (operands[1], VOIDmode)) + if (! register_operand (operands[1], VOIDmode)) FAIL; }) (define_expand "extzv" [(set (match_operand:SI 0 "register_operand" "") (zero_extract:SI (match_operand 1 "ext_register_operand" "") - (match_operand:SI 2 "const8_operand" "") - (match_operand:SI 3 "const8_operand" "")))] + (match_operand:SI 2 "immediate_operand" "") + (match_operand:SI 3 "immediate_operand" "")))] "" { /* Handle extractions from %ah et al. */ @@ -12970,24 +12706,24 @@ /* From mips.md: extract_bit_field doesn't verify that our source matches the predicate, so check it again here. */ - if (! ext_register_operand (operands[1], VOIDmode)) + if (! register_operand (operands[1], VOIDmode)) FAIL; }) (define_expand "insv" [(set (zero_extract (match_operand 0 "ext_register_operand" "") - (match_operand 1 "const8_operand" "") - (match_operand 2 "const8_operand" "")) + (match_operand 1 "immediate_operand" "") + (match_operand 2 "immediate_operand" "")) (match_operand 3 "register_operand" ""))] "" { - /* Handle insertions to %ah et al. */ + /* Handle extractions from %ah et al. */ if (INTVAL (operands[1]) != 8 || INTVAL (operands[2]) != 8) FAIL; /* From mips.md: insert_bit_field doesn't verify that our source matches the predicate, so check it again here. */ - if (! ext_register_operand (operands[0], VOIDmode)) + if (! register_operand (operands[0], VOIDmode)) FAIL; if (TARGET_64BIT) @@ -12999,146 +12735,6 @@ }) ;; %%% bts, btr, btc, bt. -;; In general these instructions are *slow* when applied to memory, -;; since they enforce atomic operation. When applied to registers, -;; it depends on the cpu implementation. They're never faster than -;; the corresponding and/ior/xor operations, so with 32-bit there's -;; no point. But in 64-bit, we can't hold the relevant immediates -;; within the instruction itself, so operating on bits in the high -;; 32-bits of a register becomes easier. -;; -;; These are slow on Nocona, but fast on Athlon64. We do require the use -;; of btrq and btcq for corner cases of post-reload expansion of absdf and -;; negdf respectively, so they can never be disabled entirely. - -(define_insn "*btsq" - [(set (zero_extract:DI (match_operand:DI 0 "register_operand" "+r") - (const_int 1) - (match_operand:DI 1 "const_0_to_63_operand" "")) - (const_int 1)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && (TARGET_USE_BT || reload_completed)" - "bts{q} %1,%0" - [(set_attr "type" "alu1")]) - -(define_insn "*btrq" - [(set (zero_extract:DI (match_operand:DI 0 "register_operand" "+r") - (const_int 1) - (match_operand:DI 1 "const_0_to_63_operand" "")) - (const_int 0)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && (TARGET_USE_BT || reload_completed)" - "btr{q} %1,%0" - [(set_attr "type" "alu1")]) - -(define_insn "*btcq" - [(set (zero_extract:DI (match_operand:DI 0 "register_operand" "+r") - (const_int 1) - (match_operand:DI 1 "const_0_to_63_operand" "")) - (not:DI (zero_extract:DI (match_dup 0) (const_int 1) (match_dup 1)))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && (TARGET_USE_BT || reload_completed)" - "btc{q} %1,%0" - [(set_attr "type" "alu1")]) - -;; Allow Nocona to avoid these instructions if a register is available. - -(define_peephole2 - [(match_scratch:DI 2 "r") - (parallel [(set (zero_extract:DI - (match_operand:DI 0 "register_operand" "") - (const_int 1) - (match_operand:DI 1 "const_0_to_63_operand" "")) - (const_int 1)) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT && !TARGET_USE_BT" - [(const_int 0)] -{ - HOST_WIDE_INT i = INTVAL (operands[1]), hi, lo; - rtx op1; - - if (HOST_BITS_PER_WIDE_INT >= 64) - lo = (HOST_WIDE_INT)1 << i, hi = 0; - else if (i < HOST_BITS_PER_WIDE_INT) - lo = (HOST_WIDE_INT)1 << i, hi = 0; - else - lo = 0, hi = (HOST_WIDE_INT)1 << (i - HOST_BITS_PER_WIDE_INT); - - op1 = immed_double_const (lo, hi, DImode); - if (i >= 31) - { - emit_move_insn (operands[2], op1); - op1 = operands[2]; - } - - emit_insn (gen_iordi3 (operands[0], operands[0], op1)); - DONE; -}) - -(define_peephole2 - [(match_scratch:DI 2 "r") - (parallel [(set (zero_extract:DI - (match_operand:DI 0 "register_operand" "") - (const_int 1) - (match_operand:DI 1 "const_0_to_63_operand" "")) - (const_int 0)) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT && !TARGET_USE_BT" - [(const_int 0)] -{ - HOST_WIDE_INT i = INTVAL (operands[1]), hi, lo; - rtx op1; - - if (HOST_BITS_PER_WIDE_INT >= 64) - lo = (HOST_WIDE_INT)1 << i, hi = 0; - else if (i < HOST_BITS_PER_WIDE_INT) - lo = (HOST_WIDE_INT)1 << i, hi = 0; - else - lo = 0, hi = (HOST_WIDE_INT)1 << (i - HOST_BITS_PER_WIDE_INT); - - op1 = immed_double_const (~lo, ~hi, DImode); - if (i >= 32) - { - emit_move_insn (operands[2], op1); - op1 = operands[2]; - } - - emit_insn (gen_anddi3 (operands[0], operands[0], op1)); - DONE; -}) - -(define_peephole2 - [(match_scratch:DI 2 "r") - (parallel [(set (zero_extract:DI - (match_operand:DI 0 "register_operand" "") - (const_int 1) - (match_operand:DI 1 "const_0_to_63_operand" "")) - (not:DI (zero_extract:DI - (match_dup 0) (const_int 1) (match_dup 1)))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT && !TARGET_USE_BT" - [(const_int 0)] -{ - HOST_WIDE_INT i = INTVAL (operands[1]), hi, lo; - rtx op1; - - if (HOST_BITS_PER_WIDE_INT >= 64) - lo = (HOST_WIDE_INT)1 << i, hi = 0; - else if (i < HOST_BITS_PER_WIDE_INT) - lo = (HOST_WIDE_INT)1 << i, hi = 0; - else - lo = 0, hi = (HOST_WIDE_INT)1 << (i - HOST_BITS_PER_WIDE_INT); - - op1 = immed_double_const (lo, hi, DImode); - if (i >= 31) - { - emit_move_insn (operands[2], op1); - op1 = operands[2]; - } - - emit_insn (gen_xordi3 (operands[0], operands[0], op1)); - DONE; -}) ;; Store-flag instructions. @@ -13151,125 +12747,125 @@ (define_expand "seq" [(set (match_operand:QI 0 "register_operand" "") - (eq:QI (reg:CC FLAGS_REG) (const_int 0)))] + (eq:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (EQ, operands[0])) DONE; else FAIL;") (define_expand "sne" [(set (match_operand:QI 0 "register_operand" "") - (ne:QI (reg:CC FLAGS_REG) (const_int 0)))] + (ne:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (NE, operands[0])) DONE; else FAIL;") (define_expand "sgt" [(set (match_operand:QI 0 "register_operand" "") - (gt:QI (reg:CC FLAGS_REG) (const_int 0)))] + (gt:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (GT, operands[0])) DONE; else FAIL;") (define_expand "sgtu" [(set (match_operand:QI 0 "register_operand" "") - (gtu:QI (reg:CC FLAGS_REG) (const_int 0)))] + (gtu:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (GTU, operands[0])) DONE; else FAIL;") (define_expand "slt" [(set (match_operand:QI 0 "register_operand" "") - (lt:QI (reg:CC FLAGS_REG) (const_int 0)))] + (lt:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (LT, operands[0])) DONE; else FAIL;") (define_expand "sltu" [(set (match_operand:QI 0 "register_operand" "") - (ltu:QI (reg:CC FLAGS_REG) (const_int 0)))] + (ltu:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (LTU, operands[0])) DONE; else FAIL;") (define_expand "sge" [(set (match_operand:QI 0 "register_operand" "") - (ge:QI (reg:CC FLAGS_REG) (const_int 0)))] + (ge:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (GE, operands[0])) DONE; else FAIL;") (define_expand "sgeu" [(set (match_operand:QI 0 "register_operand" "") - (geu:QI (reg:CC FLAGS_REG) (const_int 0)))] + (geu:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (GEU, operands[0])) DONE; else FAIL;") (define_expand "sle" [(set (match_operand:QI 0 "register_operand" "") - (le:QI (reg:CC FLAGS_REG) (const_int 0)))] + (le:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (LE, operands[0])) DONE; else FAIL;") (define_expand "sleu" [(set (match_operand:QI 0 "register_operand" "") - (leu:QI (reg:CC FLAGS_REG) (const_int 0)))] + (leu:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (LEU, operands[0])) DONE; else FAIL;") (define_expand "sunordered" [(set (match_operand:QI 0 "register_operand" "") - (unordered:QI (reg:CC FLAGS_REG) (const_int 0)))] + (unordered:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNORDERED, operands[0])) DONE; else FAIL;") (define_expand "sordered" [(set (match_operand:QI 0 "register_operand" "") - (ordered:QI (reg:CC FLAGS_REG) (const_int 0)))] + (ordered:QI (reg:CC 17) (const_int 0)))] "TARGET_80387" "if (ix86_expand_setcc (ORDERED, operands[0])) DONE; else FAIL;") (define_expand "suneq" [(set (match_operand:QI 0 "register_operand" "") - (uneq:QI (reg:CC FLAGS_REG) (const_int 0)))] + (uneq:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNEQ, operands[0])) DONE; else FAIL;") (define_expand "sunge" [(set (match_operand:QI 0 "register_operand" "") - (unge:QI (reg:CC FLAGS_REG) (const_int 0)))] + (unge:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNGE, operands[0])) DONE; else FAIL;") (define_expand "sungt" [(set (match_operand:QI 0 "register_operand" "") - (ungt:QI (reg:CC FLAGS_REG) (const_int 0)))] + (ungt:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNGT, operands[0])) DONE; else FAIL;") (define_expand "sunle" [(set (match_operand:QI 0 "register_operand" "") - (unle:QI (reg:CC FLAGS_REG) (const_int 0)))] + (unle:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNLE, operands[0])) DONE; else FAIL;") (define_expand "sunlt" [(set (match_operand:QI 0 "register_operand" "") - (unlt:QI (reg:CC FLAGS_REG) (const_int 0)))] + (unlt:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNLT, operands[0])) DONE; else FAIL;") (define_expand "sltgt" [(set (match_operand:QI 0 "register_operand" "") - (ltgt:QI (reg:CC FLAGS_REG) (const_int 0)))] + (ltgt:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (LTGT, operands[0])) DONE; else FAIL;") (define_insn "*setcc_1" [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") (match_operator:QI 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]))] + [(reg 17) (const_int 0)]))] "" "set%C1\t%0" [(set_attr "type" "setcc") (set_attr "mode" "QI")]) -(define_insn "*setcc_2" +(define_insn "setcc_2" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) (match_operator:QI 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]))] + [(reg 17) (const_int 0)]))] "" "set%C1\t%0" [(set_attr "type" "setcc") @@ -13286,7 +12882,7 @@ (define_split [(set (match_operand:QI 0 "nonimmediate_operand" "") (ne:QI (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (const_int 0)))] "" [(set (match_dup 0) (match_dup 1))] @@ -13297,7 +12893,7 @@ (define_split [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "")) (ne:QI (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (const_int 0)))] "" [(set (match_dup 0) (match_dup 1))] @@ -13308,7 +12904,7 @@ (define_split [(set (match_operand:QI 0 "nonimmediate_operand" "") (eq:QI (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (const_int 0)))] "" [(set (match_dup 0) (match_dup 1))] @@ -13316,8 +12912,8 @@ rtx new_op1 = copy_rtx (operands[1]); operands[1] = new_op1; PUT_MODE (new_op1, QImode); - PUT_CODE (new_op1, ix86_reverse_condition (GET_CODE (new_op1), - GET_MODE (XEXP (new_op1, 0)))); + PUT_CODE (new_op1, REVERSE_CONDITION (GET_CODE (new_op1), + GET_MODE (XEXP (new_op1, 0)))); /* Make sure that (a) the CCmode we have for the flags is strong enough for the reversed compare or (b) we have a valid FP compare. */ @@ -13328,7 +12924,7 @@ (define_split [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "")) (eq:QI (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (const_int 0)))] "" [(set (match_dup 0) (match_dup 1))] @@ -13336,8 +12932,8 @@ rtx new_op1 = copy_rtx (operands[1]); operands[1] = new_op1; PUT_MODE (new_op1, QImode); - PUT_CODE (new_op1, ix86_reverse_condition (GET_CODE (new_op1), - GET_MODE (XEXP (new_op1, 0)))); + PUT_CODE (new_op1, REVERSE_CONDITION (GET_CODE (new_op1), + GET_MODE (XEXP (new_op1, 0)))); /* Make sure that (a) the CCmode we have for the flags is strong enough for the reversed compare or (b) we have a valid FP compare. */ @@ -13348,14 +12944,17 @@ ;; The SSE store flag instructions saves 0 or 0xffffffff to the result. ;; subsequent logical operations are used to imitate conditional moves. ;; 0xffffffff is NaN, but not in normalized form, so we can't represent -;; it directly. +;; it directly. Further holding this value in pseudo register might bring +;; problem in implicit normalization in spill code. +;; So we don't define FLOAT_STORE_FLAG_VALUE and create these +;; instructions after reload by splitting the conditional move patterns. (define_insn "*sse_setccsf" [(set (match_operand:SF 0 "register_operand" "=x") (match_operator:SF 1 "sse_comparison_operator" [(match_operand:SF 2 "register_operand" "0") (match_operand:SF 3 "nonimmediate_operand" "xm")]))] - "TARGET_SSE" + "TARGET_SSE && reload_completed" "cmp%D1ss\t{%3, %0|%0, %3}" [(set_attr "type" "ssecmp") (set_attr "mode" "SF")]) @@ -13365,7 +12964,7 @@ (match_operator:DF 1 "sse_comparison_operator" [(match_operand:DF 2 "register_operand" "0") (match_operand:DF 3 "nonimmediate_operand" "Ym")]))] - "TARGET_SSE2" + "TARGET_SSE2 && reload_completed" "cmp%D1sd\t{%3, %0|%0, %3}" [(set_attr "type" "ssecmp") (set_attr "mode" "DF")]) @@ -13374,7 +12973,7 @@ ;; We ignore the overflow flag for signed branch instructions. ;; For all bCOND expanders, also expand the compare or test insn that -;; generates reg FLAGS_REG. Generate an equality comparison if `beq' or `bne'. +;; generates reg 17. Generate an equality comparison if `beq' or `bne'. (define_expand "beq" [(set (pc) @@ -13461,7 +13060,7 @@ (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_80387 || TARGET_SSE" "ix86_expand_branch (UNORDERED, operands[0]); DONE;") (define_expand "bordered" @@ -13469,7 +13068,7 @@ (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_80387 || TARGET_SSE" "ix86_expand_branch (ORDERED, operands[0]); DONE;") (define_expand "buneq" @@ -13477,7 +13076,7 @@ (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_80387 || TARGET_SSE" "ix86_expand_branch (UNEQ, operands[0]); DONE;") (define_expand "bunge" @@ -13485,7 +13084,7 @@ (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_80387 || TARGET_SSE" "ix86_expand_branch (UNGE, operands[0]); DONE;") (define_expand "bungt" @@ -13493,7 +13092,7 @@ (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_80387 || TARGET_SSE" "ix86_expand_branch (UNGT, operands[0]); DONE;") (define_expand "bunle" @@ -13501,7 +13100,7 @@ (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_80387 || TARGET_SSE" "ix86_expand_branch (UNLE, operands[0]); DONE;") (define_expand "bunlt" @@ -13509,7 +13108,7 @@ (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_80387 || TARGET_SSE" "ix86_expand_branch (UNLT, operands[0]); DONE;") (define_expand "bltgt" @@ -13517,13 +13116,13 @@ (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_80387 || TARGET_SSE_MATH" + "TARGET_80387 || TARGET_SSE" "ix86_expand_branch (LTGT, operands[0]); DONE;") (define_insn "*jcc_1" [(set (pc) (if_then_else (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (label_ref (match_operand 0 "" "")) (pc)))] "" @@ -13541,7 +13140,7 @@ (define_insn "*jcc_2" [(set (pc) (if_then_else (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (pc) (label_ref (match_operand 0 "" ""))))] "" @@ -13567,7 +13166,7 @@ (define_split [(set (pc) (if_then_else (ne (match_operator 0 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (const_int 0)) (label_ref (match_operand 1 "" "")) (pc)))] @@ -13583,7 +13182,7 @@ (define_split [(set (pc) (if_then_else (eq (match_operator 0 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (const_int 0)) (label_ref (match_operand 1 "" "")) (pc)))] @@ -13596,8 +13195,8 @@ rtx new_op0 = copy_rtx (operands[0]); operands[0] = new_op0; PUT_MODE (new_op0, VOIDmode); - PUT_CODE (new_op0, ix86_reverse_condition (GET_CODE (new_op0), - GET_MODE (XEXP (new_op0, 0)))); + PUT_CODE (new_op0, REVERSE_CONDITION (GET_CODE (new_op0), + GET_MODE (XEXP (new_op0, 0)))); /* Make sure that (a) the CCmode we have for the flags is strong enough for the reversed compare or (b) we have a valid FP compare. */ @@ -13609,17 +13208,18 @@ ;; during early optimization. Splitting the operation apart early makes ;; for bad code when we want to reverse the operation. -(define_insn "*fp_jcc_1_mixed" +(define_insn "*fp_jcc_1" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" - [(match_operand 1 "register_operand" "f,x") - (match_operand 2 "nonimmediate_operand" "f,xm")]) + [(match_operand 1 "register_operand" "f") + (match_operand 2 "register_operand" "f")]) (label_ref (match_operand 3 "" "")) (pc))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG))] - "TARGET_MIX_SSE_I387 - && SSE_FLOAT_MODE_P (GET_MODE (operands[1])) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "TARGET_CMOVE && TARGET_80387 + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1])) + && FLOAT_MODE_P (GET_MODE (operands[1])) && GET_MODE (operands[1]) == GET_MODE (operands[2]) && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") @@ -13627,44 +13227,44 @@ (define_insn "*fp_jcc_1_sse" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" - [(match_operand 1 "register_operand" "x") - (match_operand 2 "nonimmediate_operand" "xm")]) + [(match_operand 1 "register_operand" "f#x,x#f") + (match_operand 2 "nonimmediate_operand" "f#x,xm#f")]) (label_ref (match_operand 3 "" "")) (pc))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG))] - "TARGET_SSE_MATH + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "TARGET_80387 && SSE_FLOAT_MODE_P (GET_MODE (operands[1])) && GET_MODE (operands[1]) == GET_MODE (operands[2]) && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") -(define_insn "*fp_jcc_1_387" +(define_insn "*fp_jcc_1_sse_only" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" - [(match_operand 1 "register_operand" "f") - (match_operand 2 "register_operand" "f")]) + [(match_operand 1 "register_operand" "x") + (match_operand 2 "nonimmediate_operand" "xm")]) (label_ref (match_operand 3 "" "")) (pc))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG))] - "TARGET_CMOVE && TARGET_80387 - && FLOAT_MODE_P (GET_MODE (operands[1])) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "SSE_FLOAT_MODE_P (GET_MODE (operands[1])) && GET_MODE (operands[1]) == GET_MODE (operands[2]) && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") -(define_insn "*fp_jcc_2_mixed" +(define_insn "*fp_jcc_2" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" - [(match_operand 1 "register_operand" "f,x") - (match_operand 2 "nonimmediate_operand" "f,xm")]) + [(match_operand 1 "register_operand" "f") + (match_operand 2 "register_operand" "f")]) (pc) (label_ref (match_operand 3 "" "")))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG))] - "TARGET_MIX_SSE_I387 - && SSE_FLOAT_MODE_P (GET_MODE (operands[1])) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "TARGET_CMOVE && TARGET_80387 + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1])) + && FLOAT_MODE_P (GET_MODE (operands[1])) && GET_MODE (operands[1]) == GET_MODE (operands[2]) && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") @@ -13672,42 +13272,41 @@ (define_insn "*fp_jcc_2_sse" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" - [(match_operand 1 "register_operand" "x") - (match_operand 2 "nonimmediate_operand" "xm")]) + [(match_operand 1 "register_operand" "f#x,x#f") + (match_operand 2 "nonimmediate_operand" "f#x,xm#f")]) (pc) (label_ref (match_operand 3 "" "")))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG))] - "TARGET_SSE_MATH + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "TARGET_80387 && SSE_FLOAT_MODE_P (GET_MODE (operands[1])) && GET_MODE (operands[1]) == GET_MODE (operands[2]) && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") -(define_insn "*fp_jcc_2_387" +(define_insn "*fp_jcc_2_sse_only" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" - [(match_operand 1 "register_operand" "f") - (match_operand 2 "register_operand" "f")]) + [(match_operand 1 "register_operand" "x") + (match_operand 2 "nonimmediate_operand" "xm")]) (pc) (label_ref (match_operand 3 "" "")))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG))] - "TARGET_CMOVE && TARGET_80387 - && FLOAT_MODE_P (GET_MODE (operands[1])) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "SSE_FLOAT_MODE_P (GET_MODE (operands[1])) && GET_MODE (operands[1]) == GET_MODE (operands[2]) && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") -(define_insn "*fp_jcc_3_387" +(define_insn "*fp_jcc_3" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" [(match_operand 1 "register_operand" "f") (match_operand 2 "nonimmediate_operand" "fm")]) (label_ref (match_operand 3 "" "")) (pc))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG)) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17)) (clobber (match_scratch:HI 4 "=a"))] "TARGET_80387 && (GET_MODE (operands[1]) == SFmode || GET_MODE (operands[1]) == DFmode) @@ -13718,15 +13317,15 @@ && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") -(define_insn "*fp_jcc_4_387" +(define_insn "*fp_jcc_4" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" [(match_operand 1 "register_operand" "f") (match_operand 2 "nonimmediate_operand" "fm")]) (pc) (label_ref (match_operand 3 "" "")))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG)) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17)) (clobber (match_scratch:HI 4 "=a"))] "TARGET_80387 && (GET_MODE (operands[1]) == SFmode || GET_MODE (operands[1]) == DFmode) @@ -13737,15 +13336,15 @@ && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") -(define_insn "*fp_jcc_5_387" +(define_insn "*fp_jcc_5" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" [(match_operand 1 "register_operand" "f") (match_operand 2 "register_operand" "f")]) (label_ref (match_operand 3 "" "")) (pc))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG)) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17)) (clobber (match_scratch:HI 4 "=a"))] "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) @@ -13753,65 +13352,22 @@ && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") -(define_insn "*fp_jcc_6_387" +(define_insn "*fp_jcc_6" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" [(match_operand 1 "register_operand" "f") (match_operand 2 "register_operand" "f")]) (pc) (label_ref (match_operand 3 "" "")))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG)) - (clobber (match_scratch:HI 4 "=a"))] - "TARGET_80387 - && FLOAT_MODE_P (GET_MODE (operands[1])) - && GET_MODE (operands[1]) == GET_MODE (operands[2]) - && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" - "#") - -(define_insn "*fp_jcc_7_387" - [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operand 1 "register_operand" "f") - (match_operand 2 "const0_operand" "X")]) - (label_ref (match_operand 3 "" "")) - (pc))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG)) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17)) (clobber (match_scratch:HI 4 "=a"))] "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) && GET_MODE (operands[1]) == GET_MODE (operands[2]) - && !ix86_use_fcomi_compare (GET_CODE (operands[0])) - && SELECT_CC_MODE (GET_CODE (operands[0]), - operands[1], operands[2]) == CCFPmode && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") -;; The order of operands in *fp_jcc_8_387 is forced by combine in -;; simplify_comparison () function. Float operator is treated as RTX_OBJ -;; with a precedence over other operators and is always put in the first -;; place. Swap condition and operands to match ficom instruction. - -(define_insn "*fp_jcc_8<mode>_387" - [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operator 1 "float_operator" - [(match_operand:X87MODEI12 2 "nonimmediate_operand" "m,?r")]) - (match_operand 3 "register_operand" "f,f")]) - (label_ref (match_operand 4 "" "")) - (pc))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG)) - (clobber (match_scratch:HI 5 "=a,a"))] - "TARGET_80387 && TARGET_USE_<MODE>MODE_FIOP - && FLOAT_MODE_P (GET_MODE (operands[3])) - && GET_MODE (operands[1]) == GET_MODE (operands[3]) - && !ix86_use_fcomi_compare (swap_condition (GET_CODE (operands[0]))) - && ix86_fp_compare_mode (swap_condition (GET_CODE (operands[0]))) == CCFPmode - && ix86_fp_jump_nontrivial_p (swap_condition (GET_CODE (operands[0])))" - "#") - (define_split [(set (pc) (if_then_else (match_operator 0 "comparison_operator" @@ -13819,13 +13375,13 @@ (match_operand 2 "nonimmediate_operand" "")]) (match_operand 3 "" "") (match_operand 4 "" ""))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG))] + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] "reload_completed" [(const_int 0)] { ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2], - operands[3], operands[4], NULL_RTX, NULL_RTX); + operands[3], operands[4], NULL_RTX); DONE; }) @@ -13833,61 +13389,20 @@ [(set (pc) (if_then_else (match_operator 0 "comparison_operator" [(match_operand 1 "register_operand" "") - (match_operand 2 "general_operand" "")]) + (match_operand 2 "nonimmediate_operand" "")]) (match_operand 3 "" "") (match_operand 4 "" ""))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG)) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17)) (clobber (match_scratch:HI 5 "=a"))] "reload_completed" - [(const_int 0)] -{ - ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2], - operands[3], operands[4], operands[5], NULL_RTX); - DONE; -}) - -(define_split - [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operator 1 "float_operator" - [(match_operand:X87MODEI12 2 "memory_operand" "")]) - (match_operand 3 "register_operand" "")]) - (match_operand 4 "" "") - (match_operand 5 "" ""))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG)) - (clobber (match_scratch:HI 6 "=a"))] - "reload_completed" - [(const_int 0)] -{ - operands[7] = gen_rtx_FLOAT (GET_MODE (operands[1]), operands[2]); - ix86_split_fp_branch (swap_condition (GET_CODE (operands[0])), - operands[3], operands[7], - operands[4], operands[5], operands[6], NULL_RTX); - DONE; -}) - -;; %%% Kill this when reload knows how to do it. -(define_split [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operator 1 "float_operator" - [(match_operand:X87MODEI12 2 "register_operand" "")]) - (match_operand 3 "register_operand" "")]) - (match_operand 4 "" "") - (match_operand 5 "" ""))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG)) - (clobber (match_scratch:HI 6 "=a"))] - "reload_completed" - [(const_int 0)] + (if_then_else (match_dup 6) + (match_dup 3) + (match_dup 4)))] { - operands[7] = ix86_force_to_memory (GET_MODE (operands[2]), operands[2]); - operands[7] = gen_rtx_FLOAT (GET_MODE (operands[1]), operands[7]); - ix86_split_fp_branch (swap_condition (GET_CODE (operands[0])), - operands[3], operands[7], - operands[4], operands[5], operands[6], operands[2]); + ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2], + operands[3], operands[4], operands[5]); DONE; }) @@ -13979,13 +13494,119 @@ [(set_attr "type" "ibr") (set_attr "length_immediate" "0")]) +;; Loop instruction +;; +;; This is all complicated by the fact that since this is a jump insn +;; we must handle our own reloads. + +(define_expand "doloop_end" + [(use (match_operand 0 "" "")) ; loop pseudo + (use (match_operand 1 "" "")) ; iterations; zero if unknown + (use (match_operand 2 "" "")) ; max iterations + (use (match_operand 3 "" "")) ; loop level + (use (match_operand 4 "" ""))] ; label + "!TARGET_64BIT && TARGET_USE_LOOP" + " +{ + /* Only use cloop on innermost loops. */ + if (INTVAL (operands[3]) > 1) + FAIL; + if (GET_MODE (operands[0]) != SImode) + FAIL; + emit_jump_insn (gen_doloop_end_internal (operands[4], operands[0], + operands[0])); + DONE; +}") + +(define_insn "doloop_end_internal" + [(set (pc) + (if_then_else (ne (match_operand:SI 1 "register_operand" "c,?*r,?*r") + (const_int 1)) + (label_ref (match_operand 0 "" "")) + (pc))) + (set (match_operand:SI 2 "register_operand" "=1,1,*m*r") + (plus:SI (match_dup 1) + (const_int -1))) + (clobber (match_scratch:SI 3 "=X,X,r")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_USE_LOOP" +{ + if (which_alternative != 0) + return "#"; + if (get_attr_length (insn) == 2) + return "%+loop\t%l0"; + else + return "dec{l}\t%1\;%+jne\t%l0"; +} + [(set_attr "ppro_uops" "many") + (set (attr "length") + (if_then_else (and (eq_attr "alternative" "0") + (and (ge (minus (match_dup 0) (pc)) + (const_int -126)) + (lt (minus (match_dup 0) (pc)) + (const_int 128)))) + (const_int 2) + (const_int 16))) + ;; We don't know the type before shorten branches. Optimistically expect + ;; the loop instruction to match. + (set (attr "type") (const_string "ibr"))]) + +(define_split + [(set (pc) + (if_then_else (ne (match_operand:SI 1 "register_operand" "") + (const_int 1)) + (match_operand 0 "" "") + (pc))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (const_int -1))) + (clobber (match_scratch:SI 2 "")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_USE_LOOP + && reload_completed + && REGNO (operands[1]) != 2" + [(parallel [(set (reg:CCZ 17) + (compare:CCZ (plus:SI (match_dup 1) (const_int -1)) + (const_int 0))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int -1)))]) + (set (pc) (if_then_else (ne (reg:CCZ 17) (const_int 0)) + (match_dup 0) + (pc)))] + "") + +(define_split + [(set (pc) + (if_then_else (ne (match_operand:SI 1 "register_operand" "") + (const_int 1)) + (match_operand 0 "" "") + (pc))) + (set (match_operand:SI 2 "nonimmediate_operand" "") + (plus:SI (match_dup 1) + (const_int -1))) + (clobber (match_scratch:SI 3 "")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_USE_LOOP + && reload_completed + && (! REG_P (operands[2]) + || ! rtx_equal_p (operands[1], operands[2]))" + [(set (match_dup 3) (match_dup 1)) + (parallel [(set (reg:CCZ 17) + (compare:CCZ (plus:SI (match_dup 3) (const_int -1)) + (const_int 0))) + (set (match_dup 3) (plus:SI (match_dup 3) (const_int -1)))]) + (set (match_dup 2) (match_dup 3)) + (set (pc) (if_then_else (ne (reg:CCZ 17) (const_int 0)) + (match_dup 0) + (pc)))] + "") + ;; Convert setcc + movzbl to xor + setcc if operands don't overlap. (define_peephole2 - [(set (reg FLAGS_REG) (match_operand 0 "" "")) + [(set (reg 17) (match_operand 0 "" "")) (set (match_operand:QI 1 "register_operand" "") (match_operator:QI 2 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)])) + [(reg 17) (const_int 0)])) (set (match_operand 3 "q_regs_operand" "") (zero_extend (match_dup 1)))] "(peep2_reg_dead_p (3, operands[1]) @@ -13995,7 +13616,7 @@ (set (strict_low_part (match_dup 5)) (match_dup 2))] { - operands[4] = gen_rtx_REG (GET_MODE (operands[0]), FLAGS_REG); + operands[4] = gen_rtx_REG (GET_MODE (operands[0]), 17); operands[5] = gen_lowpart (QImode, operands[3]); ix86_expand_clear (operands[3]); }) @@ -14003,13 +13624,13 @@ ;; Similar, but match zero_extendhisi2_and, which adds a clobber. (define_peephole2 - [(set (reg FLAGS_REG) (match_operand 0 "" "")) + [(set (reg 17) (match_operand 0 "" "")) (set (match_operand:QI 1 "register_operand" "") (match_operator:QI 2 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)])) + [(reg 17) (const_int 0)])) (parallel [(set (match_operand 3 "q_regs_operand" "") (zero_extend (match_dup 1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "(peep2_reg_dead_p (3, operands[1]) || operands_match_p (operands[1], operands[3])) && ! reg_overlap_mentioned_p (operands[3], operands[0])" @@ -14017,7 +13638,7 @@ (set (strict_low_part (match_dup 5)) (match_dup 2))] { - operands[4] = gen_rtx_REG (GET_MODE (operands[0]), FLAGS_REG); + operands[4] = gen_rtx_REG (GET_MODE (operands[0]), 17); operands[5] = gen_lowpart (QImode, operands[3]); ix86_expand_clear (operands[3]); }) @@ -14033,8 +13654,8 @@ (define_expand "call_pop" [(parallel [(call (match_operand:QI 0 "" "") (match_operand:SI 1 "" "")) - (set (reg:SI SP_REG) - (plus:SI (reg:SI SP_REG) + (set (reg:SI 7) + (plus:SI (reg:SI 7) (match_operand:SI 3 "" "")))])] "!TARGET_64BIT" { @@ -14045,7 +13666,7 @@ (define_insn "*call_pop_0" [(call (mem:QI (match_operand:SI 0 "constant_call_address_operand" "")) (match_operand:SI 1 "" "")) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) + (set (reg:SI 7) (plus:SI (reg:SI 7) (match_operand:SI 2 "immediate_operand" "")))] "!TARGET_64BIT" { @@ -14059,7 +13680,7 @@ (define_insn "*call_pop_1" [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "rsm")) (match_operand:SI 1 "" "")) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) + (set (reg:SI 7) (plus:SI (reg:SI 7) (match_operand:SI 2 "immediate_operand" "i")))] "!TARGET_64BIT" { @@ -14114,7 +13735,7 @@ (match_operand 1 "" ""))] "!SIBLING_CALL_P (insn) && !TARGET_64BIT" { - if (constant_call_address_operand (operands[0], Pmode)) + if (constant_call_address_operand (operands[0], QImode)) return "call\t%P0"; return "call\t%A0"; } @@ -14125,7 +13746,7 @@ (match_operand 1 "" ""))] "SIBLING_CALL_P (insn) && !TARGET_64BIT" { - if (constant_call_address_operand (operands[0], Pmode)) + if (constant_call_address_operand (operands[0], QImode)) return "jmp\t%P0"; return "jmp\t%A0"; } @@ -14136,7 +13757,7 @@ (match_operand 1 "" ""))] "!SIBLING_CALL_P (insn) && TARGET_64BIT" { - if (constant_call_address_operand (operands[0], Pmode)) + if (constant_call_address_operand (operands[0], QImode)) return "call\t%P0"; return "call\t%A0"; } @@ -14163,8 +13784,8 @@ [(parallel [(set (match_operand 0 "" "") (call (match_operand:QI 1 "" "") (match_operand:SI 2 "" ""))) - (set (reg:SI SP_REG) - (plus:SI (reg:SI SP_REG) + (set (reg:SI 7) + (plus:SI (reg:SI 7) (match_operand:SI 4 "" "")))])] "!TARGET_64BIT" { @@ -14304,7 +13925,8 @@ "nop" [(set_attr "length" "1") (set_attr "length_immediate" "0") - (set_attr "modrm" "0")]) + (set_attr "modrm" "0") + (set_attr "ppro_uops" "one")]) ;; Align to 16-byte boundary, max skip in op0. Used to avoid ;; branch prediction penalty for the third jump in a 16-byte @@ -14319,7 +13941,7 @@ #else /* It is tempting to use ASM_OUTPUT_ALIGN here, but we don't want to do that. The align insn is used to avoid 3 jump instructions in the row to improve - branch prediction and the benefits hardly outweigh the cost of extra 8 + branch prediction and the benefits hardly outweight the cost of extra 8 nops on the average inserted by full alignment pseudo operation. */ #endif return ""; @@ -14334,30 +13956,12 @@ (define_insn "set_got" [(set (match_operand:SI 0 "register_operand" "=r") (unspec:SI [(const_int 0)] UNSPEC_SET_GOT)) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT" - { return output_set_got (operands[0], NULL_RTX); } - [(set_attr "type" "multi") - (set_attr "length" "12")]) - -(define_insn "set_got_labelled" - [(set (match_operand:SI 0 "register_operand" "=r") - (unspec:SI [(label_ref (match_operand 1 "" ""))] - UNSPEC_SET_GOT)) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT" - { return output_set_got (operands[0], operands[1]); } + { return output_set_got (operands[0]); } [(set_attr "type" "multi") (set_attr "length" "12")]) -(define_insn "set_got_rex64" - [(set (match_operand:DI 0 "register_operand" "=r") - (unspec:DI [(const_int 0)] UNSPEC_SET_GOT))] - "TARGET_64BIT" - "lea{q}\t_GLOBAL_OFFSET_TABLE_(%%rip), %0" - [(set_attr "type" "lea") - (set_attr "length" "6")]) - (define_expand "epilogue" [(const_int 1)] "" @@ -14383,17 +13987,16 @@ emit_move_insn (tmp, ra); if (Pmode == SImode) - emit_jump_insn (gen_eh_return_si (sa)); + emit_insn (gen_eh_return_si (sa)); else - emit_jump_insn (gen_eh_return_di (sa)); + emit_insn (gen_eh_return_di (sa)); emit_barrier (); DONE; }) (define_insn_and_split "eh_return_si" - [(set (pc) - (unspec [(match_operand:SI 0 "register_operand" "c")] - UNSPEC_EH_RETURN))] + [(unspec_volatile [(match_operand:SI 0 "register_operand" "c")] + UNSPECV_EH_RETURN)] "!TARGET_64BIT" "#" "reload_completed" @@ -14401,9 +14004,8 @@ "ix86_expand_epilogue (2); DONE;") (define_insn_and_split "eh_return_di" - [(set (pc) - (unspec [(match_operand:DI 0 "register_operand" "c")] - UNSPEC_EH_RETURN))] + [(unspec_volatile [(match_operand:DI 0 "register_operand" "c")] + UNSPECV_EH_RETURN)] "TARGET_64BIT" "#" "reload_completed" @@ -14411,16 +14013,16 @@ "ix86_expand_epilogue (2); DONE;") (define_insn "leave" - [(set (reg:SI SP_REG) (plus:SI (reg:SI BP_REG) (const_int 4))) - (set (reg:SI BP_REG) (mem:SI (reg:SI BP_REG))) + [(set (reg:SI 7) (plus:SI (reg:SI 6) (const_int 4))) + (set (reg:SI 6) (mem:SI (reg:SI 6))) (clobber (mem:BLK (scratch)))] "!TARGET_64BIT" "leave" [(set_attr "type" "leave")]) (define_insn "leave_rex64" - [(set (reg:DI SP_REG) (plus:DI (reg:DI BP_REG) (const_int 8))) - (set (reg:DI BP_REG) (mem:DI (reg:DI BP_REG))) + [(set (reg:DI 7) (plus:DI (reg:DI 6) (const_int 8))) + (set (reg:DI 6) (mem:DI (reg:DI 6))) (clobber (mem:BLK (scratch)))] "TARGET_64BIT" "leave" @@ -14431,7 +14033,7 @@ [(set (match_operand:SI 0 "register_operand" "") (ffs:SI (match_operand:SI 1 "nonimmediate_operand" ""))) (clobber (match_scratch:SI 2 "")) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") @@ -14439,118 +14041,73 @@ [(set (match_operand:SI 0 "register_operand" "=r") (ffs:SI (match_operand:SI 1 "nonimmediate_operand" "rm"))) (clobber (match_scratch:SI 2 "=&r")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_CMOVE" "#" "&& reload_completed" [(set (match_dup 2) (const_int -1)) - (parallel [(set (reg:CCZ FLAGS_REG) (compare:CCZ (match_dup 1) (const_int 0))) + (parallel [(set (reg:CCZ 17) (compare:CCZ (match_dup 1) (const_int 0))) (set (match_dup 0) (ctz:SI (match_dup 1)))]) (set (match_dup 0) (if_then_else:SI - (eq (reg:CCZ FLAGS_REG) (const_int 0)) + (eq (reg:CCZ 17) (const_int 0)) (match_dup 2) (match_dup 0))) (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_insn_and_split "*ffs_no_cmove" [(set (match_operand:SI 0 "nonimmediate_operand" "=r") (ffs:SI (match_operand:SI 1 "nonimmediate_operand" "rm"))) (clobber (match_scratch:SI 2 "=&q")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "#" "reload_completed" - [(parallel [(set (reg:CCZ FLAGS_REG) (compare:CCZ (match_dup 1) (const_int 0))) + [(parallel [(set (reg:CCZ 17) (compare:CCZ (match_dup 1) (const_int 0))) (set (match_dup 0) (ctz:SI (match_dup 1)))]) (set (strict_low_part (match_dup 3)) - (eq:QI (reg:CCZ FLAGS_REG) (const_int 0))) + (eq:QI (reg:CCZ 17) (const_int 0))) (parallel [(set (match_dup 2) (neg:SI (match_dup 2))) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (parallel [(set (match_dup 0) (ior:SI (match_dup 0) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] { operands[3] = gen_lowpart (QImode, operands[2]); ix86_expand_clear (operands[2]); }) (define_insn "*ffssi_1" - [(set (reg:CCZ FLAGS_REG) + [(set (reg:CCZ 17) (compare:CCZ (match_operand:SI 1 "nonimmediate_operand" "rm") (const_int 0))) (set (match_operand:SI 0 "register_operand" "=r") (ctz:SI (match_dup 1)))] "" "bsf{l}\t{%1, %0|%0, %1}" - [(set_attr "prefix_0f" "1")]) - -(define_expand "ffsdi2" - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (ffs:DI (match_operand:DI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:DI 2 "")) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT && TARGET_CMOVE" - "") - -(define_insn_and_split "*ffs_rex64" - [(set (match_operand:DI 0 "register_operand" "=r") - (ffs:DI (match_operand:DI 1 "nonimmediate_operand" "rm"))) - (clobber (match_scratch:DI 2 "=&r")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && TARGET_CMOVE" - "#" - "&& reload_completed" - [(set (match_dup 2) (const_int -1)) - (parallel [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (match_dup 1) (const_int 0))) - (set (match_dup 0) (ctz:DI (match_dup 1)))]) - (set (match_dup 0) (if_then_else:DI - (eq (reg:CCZ FLAGS_REG) (const_int 0)) - (match_dup 2) - (match_dup 0))) - (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (const_int 1))) - (clobber (reg:CC FLAGS_REG))])] - "") - -(define_insn "*ffsdi_1" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (match_operand:DI 1 "nonimmediate_operand" "rm") - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (ctz:DI (match_dup 1)))] - "TARGET_64BIT" - "bsf{q}\t{%1, %0|%0, %1}" - [(set_attr "prefix_0f" "1")]) + [(set_attr "prefix_0f" "1") + (set_attr "ppro_uops" "few")]) (define_insn "ctzsi2" [(set (match_operand:SI 0 "register_operand" "=r") (ctz:SI (match_operand:SI 1 "nonimmediate_operand" "rm"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "bsf{l}\t{%1, %0|%0, %1}" - [(set_attr "prefix_0f" "1")]) - -(define_insn "ctzdi2" - [(set (match_operand:DI 0 "register_operand" "=r") - (ctz:DI (match_operand:DI 1 "nonimmediate_operand" "rm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "bsf{q}\t{%1, %0|%0, %1}" - [(set_attr "prefix_0f" "1")]) + [(set_attr "prefix_0f" "1") + (set_attr "ppro_uops" "few")]) (define_expand "clzsi2" [(parallel [(set (match_operand:SI 0 "register_operand" "") (minus:SI (const_int 31) (clz:SI (match_operand:SI 1 "nonimmediate_operand" "")))) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (parallel [(set (match_dup 0) (xor:SI (match_dup 0) (const_int 31))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") @@ -14558,31 +14115,11 @@ [(set (match_operand:SI 0 "register_operand" "=r") (minus:SI (const_int 31) (clz:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "bsr{l}\t{%1, %0|%0, %1}" - [(set_attr "prefix_0f" "1")]) - -(define_expand "clzdi2" - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (minus:DI (const_int 63) - (clz:DI (match_operand:DI 1 "nonimmediate_operand" "")))) - (clobber (reg:CC FLAGS_REG))]) - (parallel - [(set (match_dup 0) (xor:DI (match_dup 0) (const_int 63))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" - "") - -(define_insn "*bsr_rex64" - [(set (match_operand:DI 0 "register_operand" "=r") - (minus:DI (const_int 63) - (clz:DI (match_operand:DI 1 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "bsr{q}\t{%1, %0|%0, %1}" - [(set_attr "prefix_0f" "1")]) + [(set_attr "prefix_0f" "1") + (set_attr "ppro_uops" "few")]) ;; Thread-local storage patterns for ELF. ;; @@ -14597,7 +14134,7 @@ UNSPEC_TLS_GD)) (clobber (match_scratch:SI 4 "=d")) (clobber (match_scratch:SI 5 "=c")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && TARGET_GNU_TLS" "lea{l}\t{%a2@TLSGD(,%1,1), %0|%0, %a2@TLSGD[%1*1]}\;call\t%P3" [(set_attr "type" "multi") @@ -14611,7 +14148,7 @@ UNSPEC_TLS_GD)) (clobber (match_scratch:SI 4 "=d")) (clobber (match_scratch:SI 5 "=c")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && TARGET_SUN_TLS" "lea{l}\t{%a2@DTLNDX(%1), %4|%4, %a2@DTLNDX[%1]} push{l}\t%4\;call\t%a2@TLSPLT\;pop{l}\t%4\;nop" @@ -14627,7 +14164,7 @@ UNSPEC_TLS_GD)) (clobber (match_scratch:SI 4 "")) (clobber (match_scratch:SI 5 "")) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" { if (flag_pic) @@ -14637,19 +14174,13 @@ operands[2] = gen_reg_rtx (Pmode); emit_insn (gen_set_got (operands[2])); } - if (TARGET_GNU2_TLS) - { - emit_insn (gen_tls_dynamic_gnu2_32 - (operands[0], operands[1], operands[2])); - DONE; - } operands[3] = ix86_tls_get_addr (); }) (define_insn "*tls_global_dynamic_64" [(set (match_operand:DI 0 "register_operand" "=a") - (call:DI (mem:QI (match_operand:DI 2 "call_insn_operand" "")) - (match_operand:DI 3 "" ""))) + (call (mem:QI (match_operand:DI 2 "call_insn_operand" "")) + (match_operand:DI 3 "" ""))) (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] UNSPEC_TLS_GD)] "TARGET_64BIT" @@ -14659,17 +14190,11 @@ (define_expand "tls_global_dynamic_64" [(parallel [(set (match_operand:DI 0 "register_operand" "") - (call:DI (mem:QI (match_dup 2)) (const_int 0))) + (call (mem:QI (match_dup 2)) (const_int 0))) (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] UNSPEC_TLS_GD)])] "" { - if (TARGET_GNU2_TLS) - { - emit_insn (gen_tls_dynamic_gnu2_64 - (operands[0], operands[1])); - DONE; - } operands[2] = ix86_tls_get_addr (); }) @@ -14680,7 +14205,7 @@ UNSPEC_TLS_LD_BASE)) (clobber (match_scratch:SI 3 "=d")) (clobber (match_scratch:SI 4 "=c")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && TARGET_GNU_TLS" "lea{l}\t{%&@TLSLDM(%1), %0|%0, %&@TLSLDM[%1]}\;call\t%P2" [(set_attr "type" "multi") @@ -14693,7 +14218,7 @@ UNSPEC_TLS_LD_BASE)) (clobber (match_scratch:SI 3 "=d")) (clobber (match_scratch:SI 4 "=c")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && TARGET_SUN_TLS" "lea{l}\t{%&@TMDNX(%1), %3|%3, %&@TMDNX[%1]} push{l}\t%3\;call\t%&@TLSPLT\;pop{l}\t%3" @@ -14706,7 +14231,7 @@ UNSPEC_TLS_LD_BASE)) (clobber (match_scratch:SI 3 "")) (clobber (match_scratch:SI 4 "")) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" { if (flag_pic) @@ -14716,19 +14241,13 @@ operands[1] = gen_reg_rtx (Pmode); emit_insn (gen_set_got (operands[1])); } - if (TARGET_GNU2_TLS) - { - emit_insn (gen_tls_dynamic_gnu2_32 - (operands[0], ix86_tls_module_base (), operands[1])); - DONE; - } operands[2] = ix86_tls_get_addr (); }) (define_insn "*tls_local_dynamic_base_64" [(set (match_operand:DI 0 "register_operand" "=a") - (call:DI (mem:QI (match_operand:DI 1 "call_insn_operand" "")) - (match_operand:DI 2 "" ""))) + (call (mem:QI (match_operand:DI 1 "call_insn_operand" "")) + (match_operand:DI 2 "" ""))) (unspec:DI [(const_int 0)] UNSPEC_TLS_LD_BASE)] "TARGET_64BIT" "lea{q}\t{%&@TLSLD(%%rip), %%rdi|%%rdi, %&@TLSLD[%%rip]}\;call\t%P1" @@ -14737,16 +14256,10 @@ (define_expand "tls_local_dynamic_base_64" [(parallel [(set (match_operand:DI 0 "register_operand" "") - (call:DI (mem:QI (match_dup 1)) (const_int 0))) + (call (mem:QI (match_dup 1)) (const_int 0))) (unspec:DI [(const_int 0)] UNSPEC_TLS_LD_BASE)])] "" { - if (TARGET_GNU2_TLS) - { - emit_insn (gen_tls_dynamic_gnu2_64 - (operands[0], ix86_tls_module_base ())); - DONE; - } operands[1] = ix86_tls_get_addr (); }) @@ -14763,7 +14276,7 @@ UNSPEC_DTPOFF)))) (clobber (match_scratch:SI 4 "=d")) (clobber (match_scratch:SI 5 "=c")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "#" "" @@ -14772,7 +14285,7 @@ UNSPEC_TLS_GD)) (clobber (match_dup 4)) (clobber (match_dup 5)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") ;; Load and add the thread base pointer from %gs:0. @@ -14792,7 +14305,7 @@ [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (unspec:SI [(const_int 0)] UNSPEC_TP) (match_operand:SI 1 "register_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT" "add{l}\t{%%gs:0, %0|%0, DWORD PTR %%gs:0}" [(set_attr "type" "alu") @@ -14816,7 +14329,7 @@ [(set (match_operand:DI 0 "register_operand" "=r") (plus:DI (unspec:DI [(const_int 0)] UNSPEC_TP) (match_operand:DI 1 "register_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "add{q}\t{%%fs:0, %0|%0, QWORD PTR %%fs:0}" [(set_attr "type" "alu") @@ -14824,136 +14337,6 @@ (set_attr "length" "7") (set_attr "memory" "load") (set_attr "imm_disp" "false")]) - -;; GNU2 TLS patterns can be split. - -(define_expand "tls_dynamic_gnu2_32" - [(set (match_dup 3) - (plus:SI (match_operand:SI 2 "register_operand" "") - (const:SI - (unspec:SI [(match_operand:SI 1 "tls_symbolic_operand" "")] - UNSPEC_TLSDESC)))) - (parallel - [(set (match_operand:SI 0 "register_operand" "") - (unspec:SI [(match_dup 1) (match_dup 3) - (match_dup 2) (reg:SI SP_REG)] - UNSPEC_TLSDESC)) - (clobber (reg:CC FLAGS_REG))])] - "!TARGET_64BIT && TARGET_GNU2_TLS" -{ - operands[3] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); - ix86_tls_descriptor_calls_expanded_in_cfun = true; -}) - -(define_insn "*tls_dynamic_lea_32" - [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (match_operand:SI 1 "register_operand" "b") - (const:SI - (unspec:SI [(match_operand:SI 2 "tls_symbolic_operand" "")] - UNSPEC_TLSDESC))))] - "!TARGET_64BIT && TARGET_GNU2_TLS" - "lea{l}\t{%a2@TLSDESC(%1), %0|%0, %a2@TLSDESC[%1]}" - [(set_attr "type" "lea") - (set_attr "mode" "SI") - (set_attr "length" "6") - (set_attr "length_address" "4")]) - -(define_insn "*tls_dynamic_call_32" - [(set (match_operand:SI 0 "register_operand" "=a") - (unspec:SI [(match_operand:SI 1 "tls_symbolic_operand" "") - (match_operand:SI 2 "register_operand" "0") - ;; we have to make sure %ebx still points to the GOT - (match_operand:SI 3 "register_operand" "b") - (reg:SI SP_REG)] - UNSPEC_TLSDESC)) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && TARGET_GNU2_TLS" - "call\t{*%a1@TLSCALL(%2)|[DWORD PTR [%2+%a1@TLSCALL]]}" - [(set_attr "type" "call") - (set_attr "length" "2") - (set_attr "length_address" "0")]) - -(define_insn_and_split "*tls_dynamic_gnu2_combine_32" - [(set (match_operand:SI 0 "register_operand" "=&a") - (plus:SI - (unspec:SI [(match_operand:SI 3 "tls_modbase_operand" "") - (match_operand:SI 4 "" "") - (match_operand:SI 2 "register_operand" "b") - (reg:SI SP_REG)] - UNSPEC_TLSDESC) - (const:SI (unspec:SI - [(match_operand:SI 1 "tls_symbolic_operand" "")] - UNSPEC_DTPOFF)))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && TARGET_GNU2_TLS" - "#" - "" - [(set (match_dup 0) (match_dup 5))] -{ - operands[5] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); - emit_insn (gen_tls_dynamic_gnu2_32 (operands[5], operands[1], operands[2])); -}) - -(define_expand "tls_dynamic_gnu2_64" - [(set (match_dup 2) - (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] - UNSPEC_TLSDESC)) - (parallel - [(set (match_operand:DI 0 "register_operand" "") - (unspec:DI [(match_dup 1) (match_dup 2) (reg:DI SP_REG)] - UNSPEC_TLSDESC)) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT && TARGET_GNU2_TLS" -{ - operands[2] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); - ix86_tls_descriptor_calls_expanded_in_cfun = true; -}) - -(define_insn "*tls_dynamic_lea_64" - [(set (match_operand:DI 0 "register_operand" "=r") - (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] - UNSPEC_TLSDESC))] - "TARGET_64BIT && TARGET_GNU2_TLS" - "lea{q}\t{%a1@TLSDESC(%%rip), %0|%0, %a1@TLSDESC[%%rip]}" - [(set_attr "type" "lea") - (set_attr "mode" "DI") - (set_attr "length" "7") - (set_attr "length_address" "4")]) - -(define_insn "*tls_dynamic_call_64" - [(set (match_operand:DI 0 "register_operand" "=a") - (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "") - (match_operand:DI 2 "register_operand" "0") - (reg:DI SP_REG)] - UNSPEC_TLSDESC)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && TARGET_GNU2_TLS" - "call\t{*%a1@TLSCALL(%2)|[QWORD PTR [%2+%a1@TLSCALL]]}" - [(set_attr "type" "call") - (set_attr "length" "2") - (set_attr "length_address" "0")]) - -(define_insn_and_split "*tls_dynamic_gnu2_combine_64" - [(set (match_operand:DI 0 "register_operand" "=&a") - (plus:DI - (unspec:DI [(match_operand:DI 2 "tls_modbase_operand" "") - (match_operand:DI 3 "" "") - (reg:DI SP_REG)] - UNSPEC_TLSDESC) - (const:DI (unspec:DI - [(match_operand:DI 1 "tls_symbolic_operand" "")] - UNSPEC_DTPOFF)))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && TARGET_GNU2_TLS" - "#" - "" - [(set (match_dup 0) (match_dup 4))] -{ - operands[4] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); - emit_insn (gen_tls_dynamic_gnu2_64 (operands[4], operands[1])); -}) - -;; ;; These patterns match the binary 387 instructions for addM3, subM3, ;; mulM3 and divM3. There are three patterns for each of DFmode and @@ -14965,14 +14348,28 @@ ;; Gcc is slightly more smart about handling normal two address instructions ;; so use special patterns for add and mull. +(define_insn "*fop_sf_comm_nosse" + [(set (match_operand:SF 0 "register_operand" "=f") + (match_operator:SF 3 "binary_fp_operator" + [(match_operand:SF 1 "nonimmediate_operand" "%0") + (match_operand:SF 2 "nonimmediate_operand" "fm")]))] + "TARGET_80387 && !TARGET_SSE_MATH + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c' + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (if_then_else (match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (const_string "fop"))) + (set_attr "mode" "SF")]) -(define_insn "*fop_sf_comm_mixed" - [(set (match_operand:SF 0 "register_operand" "=f,x") +(define_insn "*fop_sf_comm" + [(set (match_operand:SF 0 "register_operand" "=f#x,x#f") (match_operator:SF 3 "binary_fp_operator" [(match_operand:SF 1 "nonimmediate_operand" "%0,0") - (match_operand:SF 2 "nonimmediate_operand" "fm,xm")]))] - "TARGET_MIX_SSE_I387 - && COMMUTATIVE_ARITH_P (operands[3]) + (match_operand:SF 2 "nonimmediate_operand" "fm#x,xm#f")]))] + "TARGET_80387 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387 + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c' && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "* return output_387_binary_op (insn, operands);" [(set (attr "type") @@ -14990,8 +14387,7 @@ (match_operator:SF 3 "binary_fp_operator" [(match_operand:SF 1 "nonimmediate_operand" "%0") (match_operand:SF 2 "nonimmediate_operand" "xm")]))] - "TARGET_SSE_MATH - && COMMUTATIVE_ARITH_P (operands[3]) + "TARGET_SSE_MATH && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c' && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "* return output_387_binary_op (insn, operands);" [(set (attr "type") @@ -15000,28 +14396,94 @@ (const_string "sseadd"))) (set_attr "mode" "SF")]) -(define_insn "*fop_sf_comm_i387" - [(set (match_operand:SF 0 "register_operand" "=f") - (match_operator:SF 3 "binary_fp_operator" - [(match_operand:SF 1 "nonimmediate_operand" "%0") - (match_operand:SF 2 "nonimmediate_operand" "fm")]))] - "TARGET_80387 - && COMMUTATIVE_ARITH_P (operands[3]) +(define_insn "*fop_df_comm_nosse" + [(set (match_operand:DF 0 "register_operand" "=f") + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "nonimmediate_operand" "%0") + (match_operand:DF 2 "nonimmediate_operand" "fm")]))] + "TARGET_80387 && (!TARGET_SSE2 || !TARGET_SSE_MATH) + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c' && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "* return output_387_binary_op (insn, operands);" [(set (attr "type") (if_then_else (match_operand:SF 3 "mult_operator" "") (const_string "fmul") (const_string "fop"))) + (set_attr "mode" "DF")]) + +(define_insn "*fop_df_comm" + [(set (match_operand:DF 0 "register_operand" "=f#Y,Y#f") + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "nonimmediate_operand" "%0,0") + (match_operand:DF 2 "nonimmediate_operand" "fm#Y,Ym#f")]))] + "TARGET_80387 && TARGET_SSE_MATH && TARGET_SSE2 && TARGET_MIX_SSE_I387 + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c' + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (if_then_else (eq_attr "alternative" "1") + (if_then_else (match_operand:SF 3 "mult_operator" "") + (const_string "ssemul") + (const_string "sseadd")) + (if_then_else (match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (const_string "fop")))) + (set_attr "mode" "DF")]) + +(define_insn "*fop_df_comm_sse" + [(set (match_operand:DF 0 "register_operand" "=Y") + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "nonimmediate_operand" "%0") + (match_operand:DF 2 "nonimmediate_operand" "Ym")]))] + "TARGET_SSE2 && TARGET_SSE_MATH + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c' + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (if_then_else (match_operand:SF 3 "mult_operator" "") + (const_string "ssemul") + (const_string "sseadd"))) + (set_attr "mode" "DF")]) + +(define_insn "*fop_xf_comm" + [(set (match_operand:XF 0 "register_operand" "=f") + (match_operator:XF 3 "binary_fp_operator" + [(match_operand:XF 1 "register_operand" "%0") + (match_operand:XF 2 "register_operand" "f")]))] + "TARGET_80387 + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (if_then_else (match_operand:XF 3 "mult_operator" "") + (const_string "fmul") + (const_string "fop"))) + (set_attr "mode" "XF")]) + +(define_insn "*fop_sf_1_nosse" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (match_operator:SF 3 "binary_fp_operator" + [(match_operand:SF 1 "nonimmediate_operand" "0,fm") + (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))] + "TARGET_80387 && !TARGET_SSE_MATH + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c' + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:SF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) (set_attr "mode" "SF")]) -(define_insn "*fop_sf_1_mixed" +(define_insn "*fop_sf_1" [(set (match_operand:SF 0 "register_operand" "=f,f,x") (match_operator:SF 3 "binary_fp_operator" [(match_operand:SF 1 "nonimmediate_operand" "0,fm,0") - (match_operand:SF 2 "nonimmediate_operand" "fm,0,xm")]))] - "TARGET_MIX_SSE_I387 - && !COMMUTATIVE_ARITH_P (operands[3]) + (match_operand:SF 2 "nonimmediate_operand" "fm,0,xm#f")]))] + "TARGET_80387 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387 + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c' && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "* return output_387_binary_op (insn, operands);" [(set (attr "type") @@ -15047,7 +14509,7 @@ [(match_operand:SF 1 "register_operand" "0") (match_operand:SF 2 "nonimmediate_operand" "xm")]))] "TARGET_SSE_MATH - && !COMMUTATIVE_ARITH_P (operands[3])" + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'" "* return output_387_binary_op (insn, operands);" [(set (attr "type") (cond [(match_operand:SF 3 "mult_operator" "") @@ -15058,32 +14520,13 @@ (const_string "sseadd"))) (set_attr "mode" "SF")]) -;; This pattern is not fully shadowed by the pattern above. -(define_insn "*fop_sf_1_i387" - [(set (match_operand:SF 0 "register_operand" "=f,f") - (match_operator:SF 3 "binary_fp_operator" - [(match_operand:SF 1 "nonimmediate_operand" "0,fm") - (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))] - "TARGET_80387 && !TARGET_SSE_MATH - && !COMMUTATIVE_ARITH_P (operands[3]) - && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" - "* return output_387_binary_op (insn, operands);" - [(set (attr "type") - (cond [(match_operand:SF 3 "mult_operator" "") - (const_string "fmul") - (match_operand:SF 3 "div_operator" "") - (const_string "fdiv") - ] - (const_string "fop"))) - (set_attr "mode" "SF")]) - ;; ??? Add SSE splitters for these! -(define_insn "*fop_sf_2<mode>_i387" +(define_insn "*fop_sf_2" [(set (match_operand:SF 0 "register_operand" "=f,f") (match_operator:SF 3 "binary_fp_operator" - [(float:SF (match_operand:X87MODEI12 1 "nonimmediate_operand" "m,?r")) + [(float:SF (match_operand:SI 1 "nonimmediate_operand" "m,?r")) (match_operand:SF 2 "register_operand" "0,0")]))] - "TARGET_80387 && TARGET_USE_<MODE>MODE_FIOP && !TARGET_SSE_MATH" + "TARGET_80387 && TARGET_USE_FIOP && !TARGET_SSE_MATH" "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" [(set (attr "type") (cond [(match_operand:SF 3 "mult_operator" "") @@ -15093,14 +14536,15 @@ ] (const_string "fop"))) (set_attr "fp_int_src" "true") - (set_attr "mode" "<MODE>")]) + (set_attr "ppro_uops" "many") + (set_attr "mode" "SI")]) -(define_insn "*fop_sf_3<mode>_i387" +(define_insn "*fop_sf_3" [(set (match_operand:SF 0 "register_operand" "=f,f") (match_operator:SF 3 "binary_fp_operator" [(match_operand:SF 1 "register_operand" "0,0") - (float:SF (match_operand:X87MODEI12 2 "nonimmediate_operand" "m,?r"))]))] - "TARGET_80387 && TARGET_USE_<MODE>MODE_FIOP && !TARGET_SSE_MATH" + (float:SF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))] + "TARGET_80387 && TARGET_USE_FIOP && !TARGET_SSE_MATH" "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" [(set (attr "type") (cond [(match_operand:SF 3 "mult_operator" "") @@ -15110,72 +14554,43 @@ ] (const_string "fop"))) (set_attr "fp_int_src" "true") - (set_attr "mode" "<MODE>")]) - -(define_insn "*fop_df_comm_mixed" - [(set (match_operand:DF 0 "register_operand" "=f,Y") - (match_operator:DF 3 "binary_fp_operator" - [(match_operand:DF 1 "nonimmediate_operand" "%0,0") - (match_operand:DF 2 "nonimmediate_operand" "fm,Ym")]))] - "TARGET_SSE2 && TARGET_MIX_SSE_I387 - && COMMUTATIVE_ARITH_P (operands[3]) - && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" - "* return output_387_binary_op (insn, operands);" - [(set (attr "type") - (if_then_else (eq_attr "alternative" "1") - (if_then_else (match_operand:DF 3 "mult_operator" "") - (const_string "ssemul") - (const_string "sseadd")) - (if_then_else (match_operand:DF 3 "mult_operator" "") - (const_string "fmul") - (const_string "fop")))) - (set_attr "mode" "DF")]) + (set_attr "ppro_uops" "many") + (set_attr "mode" "SI")]) -(define_insn "*fop_df_comm_sse" - [(set (match_operand:DF 0 "register_operand" "=Y") +(define_insn "*fop_df_1_nosse" + [(set (match_operand:DF 0 "register_operand" "=f,f") (match_operator:DF 3 "binary_fp_operator" - [(match_operand:DF 1 "nonimmediate_operand" "%0") - (match_operand:DF 2 "nonimmediate_operand" "Ym")]))] - "TARGET_SSE2 && TARGET_SSE_MATH - && COMMUTATIVE_ARITH_P (operands[3]) + [(match_operand:DF 1 "nonimmediate_operand" "0,fm") + (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))] + "TARGET_80387 && (!TARGET_SSE2 || !TARGET_SSE_MATH) + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c' && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "* return output_387_binary_op (insn, operands);" [(set (attr "type") - (if_then_else (match_operand:DF 3 "mult_operator" "") - (const_string "ssemul") - (const_string "sseadd"))) + (cond [(match_operand:DF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:DF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) (set_attr "mode" "DF")]) -(define_insn "*fop_df_comm_i387" - [(set (match_operand:DF 0 "register_operand" "=f") - (match_operator:DF 3 "binary_fp_operator" - [(match_operand:DF 1 "nonimmediate_operand" "%0") - (match_operand:DF 2 "nonimmediate_operand" "fm")]))] - "TARGET_80387 - && COMMUTATIVE_ARITH_P (operands[3]) - && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" - "* return output_387_binary_op (insn, operands);" - [(set (attr "type") - (if_then_else (match_operand:DF 3 "mult_operator" "") - (const_string "fmul") - (const_string "fop"))) - (set_attr "mode" "DF")]) -(define_insn "*fop_df_1_mixed" - [(set (match_operand:DF 0 "register_operand" "=f,f,Y") +(define_insn "*fop_df_1" + [(set (match_operand:DF 0 "register_operand" "=f#Y,f#Y,Y#f") (match_operator:DF 3 "binary_fp_operator" [(match_operand:DF 1 "nonimmediate_operand" "0,fm,0") - (match_operand:DF 2 "nonimmediate_operand" "fm,0,Ym")]))] - "TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387 - && !COMMUTATIVE_ARITH_P (operands[3]) + (match_operand:DF 2 "nonimmediate_operand" "fm,0,Ym#f")]))] + "TARGET_80387 && TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387 + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c' && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "* return output_387_binary_op (insn, operands);" [(set (attr "type") (cond [(and (eq_attr "alternative" "2") - (match_operand:DF 3 "mult_operator" "")) + (match_operand:SF 3 "mult_operator" "")) (const_string "ssemul") (and (eq_attr "alternative" "2") - (match_operand:DF 3 "div_operator" "")) + (match_operand:SF 3 "div_operator" "")) (const_string "ssediv") (eq_attr "alternative" "2") (const_string "sseadd") @@ -15193,44 +14608,24 @@ [(match_operand:DF 1 "register_operand" "0") (match_operand:DF 2 "nonimmediate_operand" "Ym")]))] "TARGET_SSE2 && TARGET_SSE_MATH - && !COMMUTATIVE_ARITH_P (operands[3])" + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'" "* return output_387_binary_op (insn, operands);" [(set_attr "mode" "DF") (set (attr "type") - (cond [(match_operand:DF 3 "mult_operator" "") + (cond [(match_operand:SF 3 "mult_operator" "") (const_string "ssemul") - (match_operand:DF 3 "div_operator" "") + (match_operand:SF 3 "div_operator" "") (const_string "ssediv") ] (const_string "sseadd")))]) -;; This pattern is not fully shadowed by the pattern above. -(define_insn "*fop_df_1_i387" - [(set (match_operand:DF 0 "register_operand" "=f,f") - (match_operator:DF 3 "binary_fp_operator" - [(match_operand:DF 1 "nonimmediate_operand" "0,fm") - (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))] - "TARGET_80387 && !(TARGET_SSE2 && TARGET_SSE_MATH) - && !COMMUTATIVE_ARITH_P (operands[3]) - && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" - "* return output_387_binary_op (insn, operands);" - [(set (attr "type") - (cond [(match_operand:DF 3 "mult_operator" "") - (const_string "fmul") - (match_operand:DF 3 "div_operator" "") - (const_string "fdiv") - ] - (const_string "fop"))) - (set_attr "mode" "DF")]) - ;; ??? Add SSE splitters for these! -(define_insn "*fop_df_2<mode>_i387" +(define_insn "*fop_df_2" [(set (match_operand:DF 0 "register_operand" "=f,f") (match_operator:DF 3 "binary_fp_operator" - [(float:DF (match_operand:X87MODEI12 1 "nonimmediate_operand" "m,?r")) + [(float:DF (match_operand:SI 1 "nonimmediate_operand" "m,?r")) (match_operand:DF 2 "register_operand" "0,0")]))] - "TARGET_80387 && TARGET_USE_<MODE>MODE_FIOP - && !(TARGET_SSE2 && TARGET_SSE_MATH)" + "TARGET_80387 && TARGET_USE_FIOP && !(TARGET_SSE2 && TARGET_SSE_MATH)" "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" [(set (attr "type") (cond [(match_operand:DF 3 "mult_operator" "") @@ -15240,15 +14635,15 @@ ] (const_string "fop"))) (set_attr "fp_int_src" "true") - (set_attr "mode" "<MODE>")]) + (set_attr "ppro_uops" "many") + (set_attr "mode" "SI")]) -(define_insn "*fop_df_3<mode>_i387" +(define_insn "*fop_df_3" [(set (match_operand:DF 0 "register_operand" "=f,f") (match_operator:DF 3 "binary_fp_operator" [(match_operand:DF 1 "register_operand" "0,0") - (float:DF (match_operand:X87MODEI12 2 "nonimmediate_operand" "m,?r"))]))] - "TARGET_80387 && TARGET_USE_<MODE>MODE_FIOP - && !(TARGET_SSE2 && TARGET_SSE_MATH)" + (float:DF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))] + "TARGET_80387 && TARGET_USE_FIOP && !(TARGET_SSE2 && TARGET_SSE_MATH)" "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" [(set (attr "type") (cond [(match_operand:DF 3 "mult_operator" "") @@ -15258,14 +14653,15 @@ ] (const_string "fop"))) (set_attr "fp_int_src" "true") - (set_attr "mode" "<MODE>")]) + (set_attr "ppro_uops" "many") + (set_attr "mode" "SI")]) -(define_insn "*fop_df_4_i387" +(define_insn "*fop_df_4" [(set (match_operand:DF 0 "register_operand" "=f,f") (match_operator:DF 3 "binary_fp_operator" [(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,0")) (match_operand:DF 2 "register_operand" "0,f")]))] - "TARGET_80387 && !(TARGET_SSE2 && TARGET_SSE_MATH) + "TARGET_80387 && (!TARGET_SSE2 || !TARGET_SSE_MATH) && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" "* return output_387_binary_op (insn, operands);" [(set (attr "type") @@ -15277,7 +14673,7 @@ (const_string "fop"))) (set_attr "mode" "SF")]) -(define_insn "*fop_df_5_i387" +(define_insn "*fop_df_5" [(set (match_operand:DF 0 "register_operand" "=f,f") (match_operator:DF 3 "binary_fp_operator" [(match_operand:DF 1 "register_operand" "0,f") @@ -15294,7 +14690,7 @@ (const_string "fop"))) (set_attr "mode" "SF")]) -(define_insn "*fop_df_6_i387" +(define_insn "*fop_df_6" [(set (match_operand:DF 0 "register_operand" "=f,f") (match_operator:DF 3 "binary_fp_operator" [(float_extend:DF @@ -15312,27 +14708,13 @@ (const_string "fop"))) (set_attr "mode" "SF")]) -(define_insn "*fop_xf_comm_i387" - [(set (match_operand:XF 0 "register_operand" "=f") - (match_operator:XF 3 "binary_fp_operator" - [(match_operand:XF 1 "register_operand" "%0") - (match_operand:XF 2 "register_operand" "f")]))] - "TARGET_80387 - && COMMUTATIVE_ARITH_P (operands[3])" - "* return output_387_binary_op (insn, operands);" - [(set (attr "type") - (if_then_else (match_operand:XF 3 "mult_operator" "") - (const_string "fmul") - (const_string "fop"))) - (set_attr "mode" "XF")]) - -(define_insn "*fop_xf_1_i387" +(define_insn "*fop_xf_1" [(set (match_operand:XF 0 "register_operand" "=f,f") (match_operator:XF 3 "binary_fp_operator" [(match_operand:XF 1 "register_operand" "0,f") (match_operand:XF 2 "register_operand" "f,0")]))] "TARGET_80387 - && !COMMUTATIVE_ARITH_P (operands[3])" + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'" "* return output_387_binary_op (insn, operands);" [(set (attr "type") (cond [(match_operand:XF 3 "mult_operator" "") @@ -15343,12 +14725,12 @@ (const_string "fop"))) (set_attr "mode" "XF")]) -(define_insn "*fop_xf_2<mode>_i387" +(define_insn "*fop_xf_2" [(set (match_operand:XF 0 "register_operand" "=f,f") (match_operator:XF 3 "binary_fp_operator" - [(float:XF (match_operand:X87MODEI12 1 "nonimmediate_operand" "m,?r")) + [(float:XF (match_operand:SI 1 "nonimmediate_operand" "m,?r")) (match_operand:XF 2 "register_operand" "0,0")]))] - "TARGET_80387 && TARGET_USE_<MODE>MODE_FIOP" + "TARGET_80387 && TARGET_USE_FIOP" "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" [(set (attr "type") (cond [(match_operand:XF 3 "mult_operator" "") @@ -15358,14 +14740,15 @@ ] (const_string "fop"))) (set_attr "fp_int_src" "true") - (set_attr "mode" "<MODE>")]) + (set_attr "mode" "SI") + (set_attr "ppro_uops" "many")]) -(define_insn "*fop_xf_3<mode>_i387" +(define_insn "*fop_xf_3" [(set (match_operand:XF 0 "register_operand" "=f,f") (match_operator:XF 3 "binary_fp_operator" [(match_operand:XF 1 "register_operand" "0,0") - (float:XF (match_operand:X87MODEI12 2 "nonimmediate_operand" "m,?r"))]))] - "TARGET_80387 && TARGET_USE_<MODE>MODE_FIOP" + (float:XF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))] + "TARGET_80387 && TARGET_USE_FIOP" "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" [(set (attr "type") (cond [(match_operand:XF 3 "mult_operator" "") @@ -15375,9 +14758,10 @@ ] (const_string "fop"))) (set_attr "fp_int_src" "true") - (set_attr "mode" "<MODE>")]) + (set_attr "mode" "SI") + (set_attr "ppro_uops" "many")]) -(define_insn "*fop_xf_4_i387" +(define_insn "*fop_xf_4" [(set (match_operand:XF 0 "register_operand" "=f,f") (match_operator:XF 3 "binary_fp_operator" [(float_extend:XF (match_operand 1 "nonimmediate_operand" "fm,0")) @@ -15393,7 +14777,7 @@ (const_string "fop"))) (set_attr "mode" "SF")]) -(define_insn "*fop_xf_5_i387" +(define_insn "*fop_xf_5" [(set (match_operand:XF 0 "register_operand" "=f,f") (match_operator:XF 3 "binary_fp_operator" [(match_operand:XF 1 "register_operand" "0,f") @@ -15410,7 +14794,7 @@ (const_string "fop"))) (set_attr "mode" "SF")]) -(define_insn "*fop_xf_6_i387" +(define_insn "*fop_xf_6" [(set (match_operand:XF 0 "register_operand" "=f,f") (match_operator:XF 3 "binary_fp_operator" [(float_extend:XF @@ -15431,7 +14815,7 @@ (define_split [(set (match_operand 0 "register_operand" "") (match_operator 3 "binary_fp_operator" - [(float (match_operand:X87MODEI12 1 "register_operand" "")) + [(float (match_operand:SI 1 "register_operand" "")) (match_operand 2 "register_operand" "")]))] "TARGET_80387 && reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))" @@ -15452,7 +14836,7 @@ [(set (match_operand 0 "register_operand" "") (match_operator 3 "binary_fp_operator" [(match_operand 1 "register_operand" "") - (float (match_operand:X87MODEI12 2 "register_operand" ""))]))] + (float (match_operand:SI 2 "register_operand" ""))]))] "TARGET_80387 && reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))" [(const_int 0)] @@ -15473,16 +14857,17 @@ (define_expand "sqrtsf2" [(set (match_operand:SF 0 "register_operand" "") (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "")))] - "TARGET_USE_FANCY_MATH_387 || TARGET_SSE_MATH" + "(! TARGET_NO_FANCY_MATH_387 && TARGET_80387) || TARGET_SSE_MATH" { if (!TARGET_SSE_MATH) operands[1] = force_reg (SFmode, operands[1]); }) -(define_insn "*sqrtsf2_mixed" - [(set (match_operand:SF 0 "register_operand" "=f,x") - (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "0,xm")))] - "TARGET_USE_FANCY_MATH_387 && TARGET_MIX_SSE_I387" +(define_insn "sqrtsf2_1" + [(set (match_operand:SF 0 "register_operand" "=f#x,x#f") + (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "0#x,xm#f")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_SSE_MATH && TARGET_MIX_SSE_I387)" "@ fsqrt sqrtss\t{%1, %0|%0, %1}" @@ -15490,19 +14875,20 @@ (set_attr "mode" "SF,SF") (set_attr "athlon_decode" "direct,*")]) -(define_insn "*sqrtsf2_sse" +(define_insn "sqrtsf2_1_sse_only" [(set (match_operand:SF 0 "register_operand" "=x") (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "xm")))] - "TARGET_SSE_MATH" + "TARGET_SSE_MATH && (!TARGET_80387 || !TARGET_MIX_SSE_I387)" "sqrtss\t{%1, %0|%0, %1}" [(set_attr "type" "sse") (set_attr "mode" "SF") (set_attr "athlon_decode" "*")]) -(define_insn "*sqrtsf2_i387" +(define_insn "sqrtsf2_i387" [(set (match_operand:SF 0 "register_operand" "=f") (sqrt:SF (match_operand:SF 1 "register_operand" "0")))] - "TARGET_USE_FANCY_MATH_387" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && !TARGET_SSE_MATH" "fsqrt" [(set_attr "type" "fpspc") (set_attr "mode" "SF") @@ -15511,16 +14897,18 @@ (define_expand "sqrtdf2" [(set (match_operand:DF 0 "register_operand" "") (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "")))] - "TARGET_USE_FANCY_MATH_387 || (TARGET_SSE2 && TARGET_SSE_MATH)" + "(! TARGET_NO_FANCY_MATH_387 && TARGET_80387) + || (TARGET_SSE2 && TARGET_SSE_MATH)" { - if (!(TARGET_SSE2 && TARGET_SSE_MATH)) + if (!TARGET_SSE2 || !TARGET_SSE_MATH) operands[1] = force_reg (DFmode, operands[1]); }) -(define_insn "*sqrtdf2_mixed" - [(set (match_operand:DF 0 "register_operand" "=f,Y") - (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "0,Ym")))] - "TARGET_USE_FANCY_MATH_387 && TARGET_SSE2 && TARGET_MIX_SSE_I387" +(define_insn "sqrtdf2_1" + [(set (match_operand:DF 0 "register_operand" "=f#Y,Y#f") + (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "0#Y,Ym#f")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387)" "@ fsqrt sqrtsd\t{%1, %0|%0, %1}" @@ -15528,30 +14916,31 @@ (set_attr "mode" "DF,DF") (set_attr "athlon_decode" "direct,*")]) -(define_insn "*sqrtdf2_sse" +(define_insn "sqrtdf2_1_sse_only" [(set (match_operand:DF 0 "register_operand" "=Y") (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "Ym")))] - "TARGET_SSE2 && TARGET_SSE_MATH" + "TARGET_SSE2 && TARGET_SSE_MATH && (!TARGET_80387 || !TARGET_MIX_SSE_I387)" "sqrtsd\t{%1, %0|%0, %1}" [(set_attr "type" "sse") (set_attr "mode" "DF") (set_attr "athlon_decode" "*")]) -(define_insn "*sqrtdf2_i387" +(define_insn "sqrtdf2_i387" [(set (match_operand:DF 0 "register_operand" "=f") (sqrt:DF (match_operand:DF 1 "register_operand" "0")))] - "TARGET_USE_FANCY_MATH_387" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (!TARGET_SSE2 || !TARGET_SSE_MATH)" "fsqrt" [(set_attr "type" "fpspc") (set_attr "mode" "DF") (set_attr "athlon_decode" "direct")]) -(define_insn "*sqrtextendsfdf2_i387" +(define_insn "*sqrtextendsfdf2" [(set (match_operand:DF 0 "register_operand" "=f") (sqrt:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387)" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && !(TARGET_SSE2 && TARGET_SSE_MATH)" "fsqrt" [(set_attr "type" "fpspc") (set_attr "mode" "DF") @@ -15560,217 +14949,46 @@ (define_insn "sqrtxf2" [(set (match_operand:XF 0 "register_operand" "=f") (sqrt:XF (match_operand:XF 1 "register_operand" "0")))] - "TARGET_USE_FANCY_MATH_387" + "TARGET_80387 && !TARGET_NO_FANCY_MATH_387 + && (TARGET_IEEE_FP || flag_unsafe_math_optimizations) " "fsqrt" [(set_attr "type" "fpspc") (set_attr "mode" "XF") (set_attr "athlon_decode" "direct")]) -(define_insn "*sqrtextendsfxf2_i387" +(define_insn "*sqrtextenddfxf2" [(set (match_operand:XF 0 "register_operand" "=f") (sqrt:XF (float_extend:XF - (match_operand:SF 1 "register_operand" "0"))))] - "TARGET_USE_FANCY_MATH_387" + (match_operand:DF 1 "register_operand" "0"))))] + "TARGET_80387 && !TARGET_NO_FANCY_MATH_387" "fsqrt" [(set_attr "type" "fpspc") (set_attr "mode" "XF") (set_attr "athlon_decode" "direct")]) -(define_insn "*sqrtextenddfxf2_i387" +(define_insn "*sqrtextendsfxf2" [(set (match_operand:XF 0 "register_operand" "=f") (sqrt:XF (float_extend:XF - (match_operand:DF 1 "register_operand" "0"))))] - "TARGET_USE_FANCY_MATH_387" + (match_operand:SF 1 "register_operand" "0"))))] + "TARGET_80387 && !TARGET_NO_FANCY_MATH_387" "fsqrt" [(set_attr "type" "fpspc") (set_attr "mode" "XF") (set_attr "athlon_decode" "direct")]) -(define_insn "fpremxf4" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 2 "register_operand" "0") - (match_operand:XF 3 "register_operand" "1")] - UNSPEC_FPREM_F)) - (set (match_operand:XF 1 "register_operand" "=u") - (unspec:XF [(match_dup 2) (match_dup 3)] - UNSPEC_FPREM_U)) - (set (reg:CCFP FPSR_REG) - (unspec:CCFP [(const_int 0)] UNSPEC_NOP))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "fprem" - [(set_attr "type" "fpspc") - (set_attr "mode" "XF")]) - -(define_expand "fmodsf3" - [(use (match_operand:SF 0 "register_operand" "")) - (use (match_operand:SF 1 "register_operand" "")) - (use (match_operand:SF 2 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx label = gen_label_rtx (); - - rtx op1 = gen_reg_rtx (XFmode); - rtx op2 = gen_reg_rtx (XFmode); - - emit_insn(gen_extendsfxf2 (op1, operands[1])); - emit_insn(gen_extendsfxf2 (op2, operands[2])); - - emit_label (label); - - emit_insn (gen_fpremxf4 (op1, op2, op1, op2)); - ix86_emit_fp_unordered_jump (label); - - emit_insn (gen_truncxfsf2_i387_noop (operands[0], op1)); - DONE; -}) - -(define_expand "fmoddf3" - [(use (match_operand:DF 0 "register_operand" "")) - (use (match_operand:DF 1 "register_operand" "")) - (use (match_operand:DF 2 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx label = gen_label_rtx (); - - rtx op1 = gen_reg_rtx (XFmode); - rtx op2 = gen_reg_rtx (XFmode); - - emit_insn (gen_extenddfxf2 (op1, operands[1])); - emit_insn (gen_extenddfxf2 (op2, operands[2])); - - emit_label (label); - - emit_insn (gen_fpremxf4 (op1, op2, op1, op2)); - ix86_emit_fp_unordered_jump (label); - - emit_insn (gen_truncxfdf2_i387_noop (operands[0], op1)); - DONE; -}) - -(define_expand "fmodxf3" - [(use (match_operand:XF 0 "register_operand" "")) - (use (match_operand:XF 1 "register_operand" "")) - (use (match_operand:XF 2 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - rtx label = gen_label_rtx (); - - emit_label (label); - - emit_insn (gen_fpremxf4 (operands[1], operands[2], - operands[1], operands[2])); - ix86_emit_fp_unordered_jump (label); - - emit_move_insn (operands[0], operands[1]); - DONE; -}) - -(define_insn "fprem1xf4" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 2 "register_operand" "0") - (match_operand:XF 3 "register_operand" "1")] - UNSPEC_FPREM1_F)) - (set (match_operand:XF 1 "register_operand" "=u") - (unspec:XF [(match_dup 2) (match_dup 3)] - UNSPEC_FPREM1_U)) - (set (reg:CCFP FPSR_REG) - (unspec:CCFP [(const_int 0)] UNSPEC_NOP))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "fprem1" - [(set_attr "type" "fpspc") - (set_attr "mode" "XF")]) - -(define_expand "dremsf3" - [(use (match_operand:SF 0 "register_operand" "")) - (use (match_operand:SF 1 "register_operand" "")) - (use (match_operand:SF 2 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx label = gen_label_rtx (); - - rtx op1 = gen_reg_rtx (XFmode); - rtx op2 = gen_reg_rtx (XFmode); - - emit_insn(gen_extendsfxf2 (op1, operands[1])); - emit_insn(gen_extendsfxf2 (op2, operands[2])); - - emit_label (label); - - emit_insn (gen_fprem1xf4 (op1, op2, op1, op2)); - ix86_emit_fp_unordered_jump (label); - - emit_insn (gen_truncxfsf2_i387_noop (operands[0], op1)); - DONE; -}) - -(define_expand "dremdf3" - [(use (match_operand:DF 0 "register_operand" "")) - (use (match_operand:DF 1 "register_operand" "")) - (use (match_operand:DF 2 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx label = gen_label_rtx (); - - rtx op1 = gen_reg_rtx (XFmode); - rtx op2 = gen_reg_rtx (XFmode); - - emit_insn (gen_extenddfxf2 (op1, operands[1])); - emit_insn (gen_extenddfxf2 (op2, operands[2])); - - emit_label (label); - - emit_insn (gen_fprem1xf4 (op1, op2, op1, op2)); - ix86_emit_fp_unordered_jump (label); - - emit_insn (gen_truncxfdf2_i387_noop (operands[0], op1)); - DONE; -}) - -(define_expand "dremxf3" - [(use (match_operand:XF 0 "register_operand" "")) - (use (match_operand:XF 1 "register_operand" "")) - (use (match_operand:XF 2 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - rtx label = gen_label_rtx (); - - emit_label (label); - - emit_insn (gen_fprem1xf4 (operands[1], operands[2], - operands[1], operands[2])); - ix86_emit_fp_unordered_jump (label); - - emit_move_insn (operands[0], operands[1]); - DONE; -}) - -(define_insn "*sindf2" +(define_insn "sindf2" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(match_operand:DF 1 "register_operand" "0")] UNSPEC_SIN))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fsin" [(set_attr "type" "fpspc") (set_attr "mode" "DF")]) -(define_insn "*sinsf2" +(define_insn "sinsf2" [(set (match_operand:SF 0 "register_operand" "=f") (unspec:SF [(match_operand:SF 1 "register_operand" "0")] UNSPEC_SIN))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fsin" [(set_attr "type" "fpspc") @@ -15781,37 +14999,34 @@ (unspec:DF [(float_extend:DF (match_operand:SF 1 "register_operand" "0"))] UNSPEC_SIN))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fsin" [(set_attr "type" "fpspc") (set_attr "mode" "DF")]) -(define_insn "*sinxf2" +(define_insn "sinxf2" [(set (match_operand:XF 0 "register_operand" "=f") (unspec:XF [(match_operand:XF 1 "register_operand" "0")] UNSPEC_SIN))] - "TARGET_USE_FANCY_MATH_387 + "TARGET_80387 && !TARGET_NO_FANCY_MATH_387 && flag_unsafe_math_optimizations" "fsin" [(set_attr "type" "fpspc") (set_attr "mode" "XF")]) -(define_insn "*cosdf2" +(define_insn "cosdf2" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(match_operand:DF 1 "register_operand" "0")] UNSPEC_COS))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fcos" [(set_attr "type" "fpspc") (set_attr "mode" "DF")]) -(define_insn "*cossf2" +(define_insn "cossf2" [(set (match_operand:SF 0 "register_operand" "=f") (unspec:SF [(match_operand:SF 1 "register_operand" "0")] UNSPEC_COS))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fcos" [(set_attr "type" "fpspc") @@ -15822,324 +15037,38 @@ (unspec:DF [(float_extend:DF (match_operand:SF 1 "register_operand" "0"))] UNSPEC_COS))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fcos" [(set_attr "type" "fpspc") (set_attr "mode" "DF")]) -(define_insn "*cosxf2" +(define_insn "cosxf2" [(set (match_operand:XF 0 "register_operand" "=f") (unspec:XF [(match_operand:XF 1 "register_operand" "0")] UNSPEC_COS))] - "TARGET_USE_FANCY_MATH_387 + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fcos" [(set_attr "type" "fpspc") (set_attr "mode" "XF")]) -;; With sincos pattern defined, sin and cos builtin function will be -;; expanded to sincos pattern with one of its outputs left unused. -;; Cse pass will detected, if two sincos patterns can be combined, -;; otherwise sincos pattern will be split back to sin or cos pattern, -;; depending on the unused output. - -(define_insn "sincosdf3" - [(set (match_operand:DF 0 "register_operand" "=f") - (unspec:DF [(match_operand:DF 2 "register_operand" "0")] - UNSPEC_SINCOS_COS)) - (set (match_operand:DF 1 "register_operand" "=u") - (unspec:DF [(match_dup 2)] UNSPEC_SINCOS_SIN))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" - "fsincos" - [(set_attr "type" "fpspc") - (set_attr "mode" "DF")]) - -(define_split - [(set (match_operand:DF 0 "register_operand" "") - (unspec:DF [(match_operand:DF 2 "register_operand" "")] - UNSPEC_SINCOS_COS)) - (set (match_operand:DF 1 "register_operand" "") - (unspec:DF [(match_dup 2)] UNSPEC_SINCOS_SIN))] - "find_regno_note (insn, REG_UNUSED, REGNO (operands[0])) - && !reload_completed && !reload_in_progress" - [(set (match_dup 1) (unspec:DF [(match_dup 2)] UNSPEC_SIN))] - "") - -(define_split - [(set (match_operand:DF 0 "register_operand" "") - (unspec:DF [(match_operand:DF 2 "register_operand" "")] - UNSPEC_SINCOS_COS)) - (set (match_operand:DF 1 "register_operand" "") - (unspec:DF [(match_dup 2)] UNSPEC_SINCOS_SIN))] - "find_regno_note (insn, REG_UNUSED, REGNO (operands[1])) - && !reload_completed && !reload_in_progress" - [(set (match_dup 0) (unspec:DF [(match_dup 2)] UNSPEC_COS))] - "") - -(define_insn "sincossf3" - [(set (match_operand:SF 0 "register_operand" "=f") - (unspec:SF [(match_operand:SF 2 "register_operand" "0")] - UNSPEC_SINCOS_COS)) - (set (match_operand:SF 1 "register_operand" "=u") - (unspec:SF [(match_dup 2)] UNSPEC_SINCOS_SIN))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" - "fsincos" - [(set_attr "type" "fpspc") - (set_attr "mode" "SF")]) - -(define_split - [(set (match_operand:SF 0 "register_operand" "") - (unspec:SF [(match_operand:SF 2 "register_operand" "")] - UNSPEC_SINCOS_COS)) - (set (match_operand:SF 1 "register_operand" "") - (unspec:SF [(match_dup 2)] UNSPEC_SINCOS_SIN))] - "find_regno_note (insn, REG_UNUSED, REGNO (operands[0])) - && !reload_completed && !reload_in_progress" - [(set (match_dup 1) (unspec:SF [(match_dup 2)] UNSPEC_SIN))] - "") - -(define_split - [(set (match_operand:SF 0 "register_operand" "") - (unspec:SF [(match_operand:SF 2 "register_operand" "")] - UNSPEC_SINCOS_COS)) - (set (match_operand:SF 1 "register_operand" "") - (unspec:SF [(match_dup 2)] UNSPEC_SINCOS_SIN))] - "find_regno_note (insn, REG_UNUSED, REGNO (operands[1])) - && !reload_completed && !reload_in_progress" - [(set (match_dup 0) (unspec:SF [(match_dup 2)] UNSPEC_COS))] - "") - -(define_insn "*sincosextendsfdf3" - [(set (match_operand:DF 0 "register_operand" "=f") - (unspec:DF [(float_extend:DF - (match_operand:SF 2 "register_operand" "0"))] - UNSPEC_SINCOS_COS)) - (set (match_operand:DF 1 "register_operand" "=u") - (unspec:DF [(float_extend:DF - (match_dup 2))] UNSPEC_SINCOS_SIN))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" - "fsincos" - [(set_attr "type" "fpspc") - (set_attr "mode" "DF")]) - -(define_split - [(set (match_operand:DF 0 "register_operand" "") - (unspec:DF [(float_extend:DF - (match_operand:SF 2 "register_operand" ""))] - UNSPEC_SINCOS_COS)) - (set (match_operand:DF 1 "register_operand" "") - (unspec:DF [(float_extend:DF - (match_dup 2))] UNSPEC_SINCOS_SIN))] - "find_regno_note (insn, REG_UNUSED, REGNO (operands[0])) - && !reload_completed && !reload_in_progress" - [(set (match_dup 1) (unspec:DF [(float_extend:DF - (match_dup 2))] UNSPEC_SIN))] - "") - -(define_split - [(set (match_operand:DF 0 "register_operand" "") - (unspec:DF [(float_extend:DF - (match_operand:SF 2 "register_operand" ""))] - UNSPEC_SINCOS_COS)) - (set (match_operand:DF 1 "register_operand" "") - (unspec:DF [(float_extend:DF - (match_dup 2))] UNSPEC_SINCOS_SIN))] - "find_regno_note (insn, REG_UNUSED, REGNO (operands[1])) - && !reload_completed && !reload_in_progress" - [(set (match_dup 0) (unspec:DF [(float_extend:DF - (match_dup 2))] UNSPEC_COS))] - "") - -(define_insn "sincosxf3" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 2 "register_operand" "0")] - UNSPEC_SINCOS_COS)) - (set (match_operand:XF 1 "register_operand" "=u") - (unspec:XF [(match_dup 2)] UNSPEC_SINCOS_SIN))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "fsincos" - [(set_attr "type" "fpspc") - (set_attr "mode" "XF")]) - -(define_split - [(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_operand:XF 2 "register_operand" "")] - UNSPEC_SINCOS_COS)) - (set (match_operand:XF 1 "register_operand" "") - (unspec:XF [(match_dup 2)] UNSPEC_SINCOS_SIN))] - "find_regno_note (insn, REG_UNUSED, REGNO (operands[0])) - && !reload_completed && !reload_in_progress" - [(set (match_dup 1) (unspec:XF [(match_dup 2)] UNSPEC_SIN))] - "") - -(define_split - [(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_operand:XF 2 "register_operand" "")] - UNSPEC_SINCOS_COS)) - (set (match_operand:XF 1 "register_operand" "") - (unspec:XF [(match_dup 2)] UNSPEC_SINCOS_SIN))] - "find_regno_note (insn, REG_UNUSED, REGNO (operands[1])) - && !reload_completed && !reload_in_progress" - [(set (match_dup 0) (unspec:XF [(match_dup 2)] UNSPEC_COS))] - "") - -(define_insn "*tandf3_1" - [(set (match_operand:DF 0 "register_operand" "=f") - (unspec:DF [(match_operand:DF 2 "register_operand" "0")] - UNSPEC_TAN_ONE)) - (set (match_operand:DF 1 "register_operand" "=u") - (unspec:DF [(match_dup 2)] UNSPEC_TAN_TAN))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" - "fptan" - [(set_attr "type" "fpspc") - (set_attr "mode" "DF")]) - -;; optimize sequence: fptan -;; fstp %st(0) -;; fld1 -;; into fptan insn. - -(define_peephole2 - [(parallel[(set (match_operand:DF 0 "register_operand" "") - (unspec:DF [(match_operand:DF 2 "register_operand" "")] - UNSPEC_TAN_ONE)) - (set (match_operand:DF 1 "register_operand" "") - (unspec:DF [(match_dup 2)] UNSPEC_TAN_TAN))]) - (set (match_dup 0) - (match_operand:DF 3 "immediate_operand" ""))] - "standard_80387_constant_p (operands[3]) == 2" - [(parallel[(set (match_dup 0) (unspec:DF [(match_dup 2)] UNSPEC_TAN_ONE)) - (set (match_dup 1) (unspec:DF [(match_dup 2)] UNSPEC_TAN_TAN))])] - "") - -(define_expand "tandf2" - [(parallel [(set (match_dup 2) - (unspec:DF [(match_operand:DF 1 "register_operand" "")] - UNSPEC_TAN_ONE)) - (set (match_operand:DF 0 "register_operand" "") - (unspec:DF [(match_dup 1)] UNSPEC_TAN_TAN))])] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (DFmode); -}) - -(define_insn "*tansf3_1" - [(set (match_operand:SF 0 "register_operand" "=f") - (unspec:SF [(match_operand:SF 2 "register_operand" "0")] - UNSPEC_TAN_ONE)) - (set (match_operand:SF 1 "register_operand" "=u") - (unspec:SF [(match_dup 2)] UNSPEC_TAN_TAN))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" - "fptan" - [(set_attr "type" "fpspc") - (set_attr "mode" "SF")]) - -;; optimize sequence: fptan -;; fstp %st(0) -;; fld1 -;; into fptan insn. - -(define_peephole2 - [(parallel[(set (match_operand:SF 0 "register_operand" "") - (unspec:SF [(match_operand:SF 2 "register_operand" "")] - UNSPEC_TAN_ONE)) - (set (match_operand:SF 1 "register_operand" "") - (unspec:SF [(match_dup 2)] UNSPEC_TAN_TAN))]) - (set (match_dup 0) - (match_operand:SF 3 "immediate_operand" ""))] - "standard_80387_constant_p (operands[3]) == 2" - [(parallel[(set (match_dup 0) (unspec:SF [(match_dup 2)] UNSPEC_TAN_ONE)) - (set (match_dup 1) (unspec:SF [(match_dup 2)] UNSPEC_TAN_TAN))])] - "") - -(define_expand "tansf2" - [(parallel [(set (match_dup 2) - (unspec:SF [(match_operand:SF 1 "register_operand" "")] - UNSPEC_TAN_ONE)) - (set (match_operand:SF 0 "register_operand" "") - (unspec:SF [(match_dup 1)] UNSPEC_TAN_TAN))])] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (SFmode); -}) - -(define_insn "*tanxf3_1" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 2 "register_operand" "0")] - UNSPEC_TAN_ONE)) - (set (match_operand:XF 1 "register_operand" "=u") - (unspec:XF [(match_dup 2)] UNSPEC_TAN_TAN))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "fptan" - [(set_attr "type" "fpspc") - (set_attr "mode" "XF")]) - -;; optimize sequence: fptan -;; fstp %st(0) -;; fld1 -;; into fptan insn. - -(define_peephole2 - [(parallel[(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_operand:XF 2 "register_operand" "")] - UNSPEC_TAN_ONE)) - (set (match_operand:XF 1 "register_operand" "") - (unspec:XF [(match_dup 2)] UNSPEC_TAN_TAN))]) - (set (match_dup 0) - (match_operand:XF 3 "immediate_operand" ""))] - "standard_80387_constant_p (operands[3]) == 2" - [(parallel[(set (match_dup 0) (unspec:XF [(match_dup 2)] UNSPEC_TAN_ONE)) - (set (match_dup 1) (unspec:XF [(match_dup 2)] UNSPEC_TAN_TAN))])] - "") - -(define_expand "tanxf2" - [(parallel [(set (match_dup 2) - (unspec:XF [(match_operand:XF 1 "register_operand" "")] - UNSPEC_TAN_ONE)) - (set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_dup 1)] UNSPEC_TAN_TAN))])] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (XFmode); -}) - (define_insn "atan2df3_1" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(match_operand:DF 2 "register_operand" "0") (match_operand:DF 1 "register_operand" "u")] UNSPEC_FPATAN)) (clobber (match_scratch:DF 3 "=1"))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fpatan" [(set_attr "type" "fpspc") (set_attr "mode" "DF")]) (define_expand "atan2df3" - [(use (match_operand:DF 0 "register_operand" "")) - (use (match_operand:DF 2 "register_operand" "")) - (use (match_operand:DF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) + [(use (match_operand:DF 0 "register_operand" "=f")) + (use (match_operand:DF 2 "register_operand" "0")) + (use (match_operand:DF 1 "register_operand" "u"))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { rtx copy = gen_reg_rtx (DFmode); @@ -16148,39 +15077,23 @@ DONE; }) -(define_expand "atandf2" - [(parallel [(set (match_operand:DF 0 "register_operand" "") - (unspec:DF [(match_dup 2) - (match_operand:DF 1 "register_operand" "")] - UNSPEC_FPATAN)) - (clobber (match_scratch:DF 3 ""))])] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (DFmode); - emit_move_insn (operands[2], CONST1_RTX (DFmode)); /* fld1 */ -}) - (define_insn "atan2sf3_1" [(set (match_operand:SF 0 "register_operand" "=f") (unspec:SF [(match_operand:SF 2 "register_operand" "0") (match_operand:SF 1 "register_operand" "u")] UNSPEC_FPATAN)) (clobber (match_scratch:SF 3 "=1"))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fpatan" [(set_attr "type" "fpspc") (set_attr "mode" "SF")]) (define_expand "atan2sf3" - [(use (match_operand:SF 0 "register_operand" "")) - (use (match_operand:SF 2 "register_operand" "")) - (use (match_operand:SF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) + [(use (match_operand:SF 0 "register_operand" "=f")) + (use (match_operand:SF 2 "register_operand" "0")) + (use (match_operand:SF 1 "register_operand" "u"))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { rtx copy = gen_reg_rtx (SFmode); @@ -16189,37 +15102,23 @@ DONE; }) -(define_expand "atansf2" - [(parallel [(set (match_operand:SF 0 "register_operand" "") - (unspec:SF [(match_dup 2) - (match_operand:SF 1 "register_operand" "")] - UNSPEC_FPATAN)) - (clobber (match_scratch:SF 3 ""))])] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (SFmode); - emit_move_insn (operands[2], CONST1_RTX (SFmode)); /* fld1 */ -}) - (define_insn "atan2xf3_1" [(set (match_operand:XF 0 "register_operand" "=f") (unspec:XF [(match_operand:XF 2 "register_operand" "0") (match_operand:XF 1 "register_operand" "u")] UNSPEC_FPATAN)) (clobber (match_scratch:XF 3 "=1"))] - "TARGET_USE_FANCY_MATH_387 + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fpatan" [(set_attr "type" "fpspc") (set_attr "mode" "XF")]) (define_expand "atan2xf3" - [(use (match_operand:XF 0 "register_operand" "")) - (use (match_operand:XF 2 "register_operand" "")) - (use (match_operand:XF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 + [(use (match_operand:XF 0 "register_operand" "=f")) + (use (match_operand:XF 2 "register_operand" "0")) + (use (match_operand:XF 1 "register_operand" "u"))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { rtx copy = gen_reg_rtx (XFmode); @@ -16228,221 +15127,63 @@ DONE; }) -(define_expand "atanxf2" - [(parallel [(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_dup 2) - (match_operand:XF 1 "register_operand" "")] - UNSPEC_FPATAN)) - (clobber (match_scratch:XF 3 ""))])] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (XFmode); - emit_move_insn (operands[2], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "asindf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:DF 1 "register_operand" ""))) - (set (match_dup 3) (mult:XF (match_dup 2) (match_dup 2))) - (set (match_dup 5) (minus:XF (match_dup 4) (match_dup 3))) - (set (match_dup 6) (sqrt:XF (match_dup 5))) - (parallel [(set (match_dup 7) - (unspec:XF [(match_dup 6) (match_dup 2)] - UNSPEC_FPATAN)) - (clobber (match_scratch:XF 8 ""))]) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 7)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - int i; - - for (i=2; i<8; i++) - operands[i] = gen_reg_rtx (XFmode); - - emit_move_insn (operands[4], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "asinsf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:SF 1 "register_operand" ""))) - (set (match_dup 3) (mult:XF (match_dup 2) (match_dup 2))) - (set (match_dup 5) (minus:XF (match_dup 4) (match_dup 3))) - (set (match_dup 6) (sqrt:XF (match_dup 5))) - (parallel [(set (match_dup 7) - (unspec:XF [(match_dup 6) (match_dup 2)] - UNSPEC_FPATAN)) - (clobber (match_scratch:XF 8 ""))]) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 7)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - int i; - - for (i=2; i<8; i++) - operands[i] = gen_reg_rtx (XFmode); - - emit_move_insn (operands[4], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "asinxf2" - [(set (match_dup 2) - (mult:XF (match_operand:XF 1 "register_operand" "") - (match_dup 1))) - (set (match_dup 4) (minus:XF (match_dup 3) (match_dup 2))) - (set (match_dup 5) (sqrt:XF (match_dup 4))) - (parallel [(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_dup 5) (match_dup 1)] - UNSPEC_FPATAN)) - (clobber (match_scratch:XF 6 ""))])] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - int i; - - for (i=2; i<6; i++) - operands[i] = gen_reg_rtx (XFmode); - - emit_move_insn (operands[3], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "acosdf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:DF 1 "register_operand" ""))) - (set (match_dup 3) (mult:XF (match_dup 2) (match_dup 2))) - (set (match_dup 5) (minus:XF (match_dup 4) (match_dup 3))) - (set (match_dup 6) (sqrt:XF (match_dup 5))) - (parallel [(set (match_dup 7) - (unspec:XF [(match_dup 2) (match_dup 6)] - UNSPEC_FPATAN)) - (clobber (match_scratch:XF 8 ""))]) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 7)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - int i; - - for (i=2; i<8; i++) - operands[i] = gen_reg_rtx (XFmode); - - emit_move_insn (operands[4], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "acossf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:SF 1 "register_operand" ""))) - (set (match_dup 3) (mult:XF (match_dup 2) (match_dup 2))) - (set (match_dup 5) (minus:XF (match_dup 4) (match_dup 3))) - (set (match_dup 6) (sqrt:XF (match_dup 5))) - (parallel [(set (match_dup 7) - (unspec:XF [(match_dup 2) (match_dup 6)] - UNSPEC_FPATAN)) - (clobber (match_scratch:XF 8 ""))]) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 7)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) +(define_insn "*fyl2x_sfxf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (unspec:SF [(match_operand:SF 2 "register_operand" "0") + (match_operand:XF 1 "register_operand" "u")] + UNSPEC_FYL2X)) + (clobber (match_scratch:SF 3 "=1"))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" -{ - int i; - - for (i=2; i<8; i++) - operands[i] = gen_reg_rtx (XFmode); - - emit_move_insn (operands[4], CONST1_RTX (XFmode)); /* fld1 */ -}) + "fyl2x" + [(set_attr "type" "fpspc") + (set_attr "mode" "SF")]) -(define_expand "acosxf2" - [(set (match_dup 2) - (mult:XF (match_operand:XF 1 "register_operand" "") - (match_dup 1))) - (set (match_dup 4) (minus:XF (match_dup 3) (match_dup 2))) - (set (match_dup 5) (sqrt:XF (match_dup 4))) - (parallel [(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_dup 1) (match_dup 5)] - UNSPEC_FPATAN)) - (clobber (match_scratch:XF 6 ""))])] - "TARGET_USE_FANCY_MATH_387 +(define_insn "*fyl2x_dfxf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(match_operand:DF 2 "register_operand" "0") + (match_operand:XF 1 "register_operand" "u")] + UNSPEC_FYL2X)) + (clobber (match_scratch:DF 3 "=1"))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" -{ - int i; - - for (i=2; i<6; i++) - operands[i] = gen_reg_rtx (XFmode); - - emit_move_insn (operands[3], CONST1_RTX (XFmode)); /* fld1 */ -}) + "fyl2x" + [(set_attr "type" "fpspc") + (set_attr "mode" "DF")]) -(define_insn "fyl2x_xf3" +(define_insn "*fyl2x_xf3" [(set (match_operand:XF 0 "register_operand" "=f") (unspec:XF [(match_operand:XF 2 "register_operand" "0") (match_operand:XF 1 "register_operand" "u")] UNSPEC_FYL2X)) (clobber (match_scratch:XF 3 "=1"))] - "TARGET_USE_FANCY_MATH_387 + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "fyl2x" [(set_attr "type" "fpspc") (set_attr "mode" "XF")]) (define_expand "logsf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:SF 1 "register_operand" ""))) - (parallel [(set (match_dup 4) - (unspec:XF [(match_dup 2) - (match_dup 3)] UNSPEC_FYL2X)) - (clobber (match_scratch:XF 5 ""))]) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 4)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) + [(parallel [(set (match_operand:SF 0 "register_operand" "") + (unspec:SF [(match_operand:SF 1 "register_operand" "") + (match_dup 2)] UNSPEC_FYL2X)) + (clobber (match_scratch:SF 3 ""))])] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { rtx temp; operands[2] = gen_reg_rtx (XFmode); - operands[3] = gen_reg_rtx (XFmode); - operands[4] = gen_reg_rtx (XFmode); - temp = standard_80387_constant_rtx (4); /* fldln2 */ - emit_move_insn (operands[3], temp); + emit_move_insn (operands[2], temp); }) (define_expand "logdf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:DF 1 "register_operand" ""))) - (parallel [(set (match_dup 4) - (unspec:XF [(match_dup 2) - (match_dup 3)] UNSPEC_FYL2X)) - (clobber (match_scratch:XF 5 ""))]) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 4)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx temp; - - operands[2] = gen_reg_rtx (XFmode); - operands[3] = gen_reg_rtx (XFmode); - operands[4] = gen_reg_rtx (XFmode); - - temp = standard_80387_constant_rtx (4); /* fldln2 */ - emit_move_insn (operands[3], temp); -}) - -(define_expand "logxf2" - [(parallel [(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_operand:XF 1 "register_operand" "") + [(parallel [(set (match_operand:DF 0 "register_operand" "") + (unspec:DF [(match_operand:DF 1 "register_operand" "") (match_dup 2)] UNSPEC_FYL2X)) - (clobber (match_scratch:XF 3 ""))])] - "TARGET_USE_FANCY_MATH_387 + (clobber (match_scratch:DF 3 ""))])] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { rtx temp; @@ -16452,274 +15193,77 @@ emit_move_insn (operands[2], temp); }) -(define_expand "log10sf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:SF 1 "register_operand" ""))) - (parallel [(set (match_dup 4) - (unspec:XF [(match_dup 2) - (match_dup 3)] UNSPEC_FYL2X)) - (clobber (match_scratch:XF 5 ""))]) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 4)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx temp; - - operands[2] = gen_reg_rtx (XFmode); - operands[3] = gen_reg_rtx (XFmode); - operands[4] = gen_reg_rtx (XFmode); - - temp = standard_80387_constant_rtx (3); /* fldlg2 */ - emit_move_insn (operands[3], temp); -}) - -(define_expand "log10df2" - [(set (match_dup 2) - (float_extend:XF (match_operand:DF 1 "register_operand" ""))) - (parallel [(set (match_dup 4) - (unspec:XF [(match_dup 2) - (match_dup 3)] UNSPEC_FYL2X)) - (clobber (match_scratch:XF 5 ""))]) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 4)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx temp; - - operands[2] = gen_reg_rtx (XFmode); - operands[3] = gen_reg_rtx (XFmode); - operands[4] = gen_reg_rtx (XFmode); - - temp = standard_80387_constant_rtx (3); /* fldlg2 */ - emit_move_insn (operands[3], temp); -}) - -(define_expand "log10xf2" +(define_expand "logxf2" [(parallel [(set (match_operand:XF 0 "register_operand" "") (unspec:XF [(match_operand:XF 1 "register_operand" "") (match_dup 2)] UNSPEC_FYL2X)) (clobber (match_scratch:XF 3 ""))])] - "TARGET_USE_FANCY_MATH_387 + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { rtx temp; operands[2] = gen_reg_rtx (XFmode); - temp = standard_80387_constant_rtx (3); /* fldlg2 */ + temp = standard_80387_constant_rtx (4); /* fldln2 */ emit_move_insn (operands[2], temp); }) -(define_expand "log2sf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:SF 1 "register_operand" ""))) - (parallel [(set (match_dup 4) - (unspec:XF [(match_dup 2) - (match_dup 3)] UNSPEC_FYL2X)) - (clobber (match_scratch:XF 5 ""))]) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 4)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (XFmode); - operands[3] = gen_reg_rtx (XFmode); - operands[4] = gen_reg_rtx (XFmode); - - emit_move_insn (operands[3], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "log2df2" - [(set (match_dup 2) - (float_extend:XF (match_operand:DF 1 "register_operand" ""))) - (parallel [(set (match_dup 4) - (unspec:XF [(match_dup 2) - (match_dup 3)] UNSPEC_FYL2X)) - (clobber (match_scratch:XF 5 ""))]) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 4)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) +(define_insn "*fscale_sfxf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (unspec:SF [(match_operand:XF 2 "register_operand" "0") + (match_operand:XF 1 "register_operand" "u")] + UNSPEC_FSCALE)) + (clobber (match_scratch:SF 3 "=1"))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (XFmode); - operands[3] = gen_reg_rtx (XFmode); - operands[4] = gen_reg_rtx (XFmode); - - emit_move_insn (operands[3], CONST1_RTX (XFmode)); /* fld1 */ -}) + "fscale\;fstp\t%y1" + [(set_attr "type" "fpspc") + (set_attr "mode" "SF")]) -(define_expand "log2xf2" - [(parallel [(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_operand:XF 1 "register_operand" "") - (match_dup 2)] UNSPEC_FYL2X)) - (clobber (match_scratch:XF 3 ""))])] - "TARGET_USE_FANCY_MATH_387 +(define_insn "*fscale_dfxf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(match_operand:XF 2 "register_operand" "0") + (match_operand:XF 1 "register_operand" "u")] + UNSPEC_FSCALE)) + (clobber (match_scratch:DF 3 "=1"))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (XFmode); - emit_move_insn (operands[2], CONST1_RTX (XFmode)); /* fld1 */ -}) + "fscale\;fstp\t%y1" + [(set_attr "type" "fpspc") + (set_attr "mode" "DF")]) -(define_insn "fyl2xp1_xf3" +(define_insn "*fscale_xf3" [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 2 "register_operand" "0") + (unspec:XF [(match_operand:XF 2 "register_operand" "0") (match_operand:XF 1 "register_operand" "u")] - UNSPEC_FYL2XP1)) + UNSPEC_FSCALE)) (clobber (match_scratch:XF 3 "=1"))] - "TARGET_USE_FANCY_MATH_387 + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" - "fyl2xp1" + "fscale\;fstp\t%y1" [(set_attr "type" "fpspc") (set_attr "mode" "XF")]) -(define_expand "log1psf2" - [(use (match_operand:SF 0 "register_operand" "")) - (use (match_operand:SF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extendsfxf2 (op1, operands[1])); - ix86_emit_i387_log1p (op0, op1); - emit_insn (gen_truncxfsf2_i387_noop (operands[0], op0)); - DONE; -}) - -(define_expand "log1pdf2" - [(use (match_operand:DF 0 "register_operand" "")) - (use (match_operand:DF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extenddfxf2 (op1, operands[1])); - ix86_emit_i387_log1p (op0, op1); - emit_insn (gen_truncxfdf2_i387_noop (operands[0], op0)); - DONE; -}) - -(define_expand "log1pxf2" - [(use (match_operand:XF 0 "register_operand" "")) - (use (match_operand:XF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - ix86_emit_i387_log1p (operands[0], operands[1]); - DONE; -}) - -(define_insn "*fxtractxf3" +(define_insn "*frndintxf2" [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 2 "register_operand" "0")] - UNSPEC_XTRACT_FRACT)) - (set (match_operand:XF 1 "register_operand" "=u") - (unspec:XF [(match_dup 2)] UNSPEC_XTRACT_EXP))] - "TARGET_USE_FANCY_MATH_387 + (unspec:XF [(match_operand:XF 1 "register_operand" "0")] + UNSPEC_FRNDINT))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" - "fxtract" + "frndint" [(set_attr "type" "fpspc") (set_attr "mode" "XF")]) -(define_expand "logbsf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:SF 1 "register_operand" ""))) - (parallel [(set (match_dup 3) - (unspec:XF [(match_dup 2)] UNSPEC_XTRACT_FRACT)) - (set (match_dup 4) - (unspec:XF [(match_dup 2)] UNSPEC_XTRACT_EXP))]) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 4)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (XFmode); - operands[3] = gen_reg_rtx (XFmode); - operands[4] = gen_reg_rtx (XFmode); -}) - -(define_expand "logbdf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:DF 1 "register_operand" ""))) - (parallel [(set (match_dup 3) - (unspec:XF [(match_dup 2)] UNSPEC_XTRACT_FRACT)) - (set (match_dup 4) - (unspec:XF [(match_dup 2)] UNSPEC_XTRACT_EXP))]) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 4)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (XFmode); - operands[3] = gen_reg_rtx (XFmode); - operands[4] = gen_reg_rtx (XFmode); -}) - -(define_expand "logbxf2" - [(parallel [(set (match_dup 2) - (unspec:XF [(match_operand:XF 1 "register_operand" "")] - UNSPEC_XTRACT_FRACT)) - (set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_dup 1)] UNSPEC_XTRACT_EXP))])] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (XFmode); -}) - -(define_expand "ilogbsi2" - [(parallel [(set (match_dup 2) - (unspec:XF [(match_operand:XF 1 "register_operand" "")] - UNSPEC_XTRACT_FRACT)) - (set (match_operand:XF 3 "register_operand" "") - (unspec:XF [(match_dup 1)] UNSPEC_XTRACT_EXP))]) - (parallel [(set (match_operand:SI 0 "register_operand" "") - (fix:SI (match_dup 3))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - operands[2] = gen_reg_rtx (XFmode); - operands[3] = gen_reg_rtx (XFmode); -}) - (define_insn "*f2xm1xf2" [(set (match_operand:XF 0 "register_operand" "=f") (unspec:XF [(match_operand:XF 1 "register_operand" "0")] UNSPEC_F2XM1))] - "TARGET_USE_FANCY_MATH_387 + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" "f2xm1" [(set_attr "type" "fpspc") (set_attr "mode" "XF")]) -(define_insn "*fscalexf4" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 2 "register_operand" "0") - (match_operand:XF 3 "register_operand" "1")] - UNSPEC_FSCALE_FRACT)) - (set (match_operand:XF 1 "register_operand" "=u") - (unspec:XF [(match_dup 2) (match_dup 3)] - UNSPEC_FSCALE_EXP))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "fscale" - [(set_attr "type" "fpspc") - (set_attr "mode" "XF")]) - (define_expand "expsf2" [(set (match_dup 2) (float_extend:XF (match_operand:SF 1 "register_operand" ""))) @@ -16728,22 +15272,16 @@ (set (match_dup 6) (minus:XF (match_dup 4) (match_dup 5))) (set (match_dup 7) (unspec:XF [(match_dup 6)] UNSPEC_F2XM1)) (set (match_dup 9) (plus:XF (match_dup 7) (match_dup 8))) - (parallel [(set (match_dup 10) - (unspec:XF [(match_dup 9) (match_dup 5)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 11) - (unspec:XF [(match_dup 9) (match_dup 5)] - UNSPEC_FSCALE_EXP))]) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 10)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) + (parallel [(set (match_operand:SF 0 "register_operand" "") + (unspec:SF [(match_dup 9) (match_dup 5)] UNSPEC_FSCALE)) + (clobber (match_scratch:SF 5 ""))])] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { rtx temp; int i; - for (i=2; i<12; i++) + for (i=2; i<10; i++) operands[i] = gen_reg_rtx (XFmode); temp = standard_80387_constant_rtx (5); /* fldl2e */ emit_move_insn (operands[3], temp); @@ -16758,42 +15296,10 @@ (set (match_dup 6) (minus:XF (match_dup 4) (match_dup 5))) (set (match_dup 7) (unspec:XF [(match_dup 6)] UNSPEC_F2XM1)) (set (match_dup 9) (plus:XF (match_dup 7) (match_dup 8))) - (parallel [(set (match_dup 10) - (unspec:XF [(match_dup 9) (match_dup 5)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 11) - (unspec:XF [(match_dup 9) (match_dup 5)] - UNSPEC_FSCALE_EXP))]) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 10)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx temp; - int i; - - for (i=2; i<12; i++) - operands[i] = gen_reg_rtx (XFmode); - temp = standard_80387_constant_rtx (5); /* fldl2e */ - emit_move_insn (operands[3], temp); - emit_move_insn (operands[8], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "expxf2" - [(set (match_dup 3) (mult:XF (match_operand:XF 1 "register_operand" "") - (match_dup 2))) - (set (match_dup 4) (unspec:XF [(match_dup 3)] UNSPEC_FRNDINT)) - (set (match_dup 5) (minus:XF (match_dup 3) (match_dup 4))) - (set (match_dup 6) (unspec:XF [(match_dup 5)] UNSPEC_F2XM1)) - (set (match_dup 8) (plus:XF (match_dup 6) (match_dup 7))) - (parallel [(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_dup 8) (match_dup 4)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 9) - (unspec:XF [(match_dup 8) (match_dup 4)] - UNSPEC_FSCALE_EXP))])] - "TARGET_USE_FANCY_MATH_387 + (parallel [(set (match_operand:DF 0 "register_operand" "") + (unspec:DF [(match_dup 9) (match_dup 5)] UNSPEC_FSCALE)) + (clobber (match_scratch:DF 5 ""))])] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { rtx temp; @@ -16802,71 +15308,11 @@ for (i=2; i<10; i++) operands[i] = gen_reg_rtx (XFmode); temp = standard_80387_constant_rtx (5); /* fldl2e */ - emit_move_insn (operands[2], temp); - emit_move_insn (operands[7], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "exp10sf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:SF 1 "register_operand" ""))) - (set (match_dup 4) (mult:XF (match_dup 2) (match_dup 3))) - (set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_FRNDINT)) - (set (match_dup 6) (minus:XF (match_dup 4) (match_dup 5))) - (set (match_dup 7) (unspec:XF [(match_dup 6)] UNSPEC_F2XM1)) - (set (match_dup 9) (plus:XF (match_dup 7) (match_dup 8))) - (parallel [(set (match_dup 10) - (unspec:XF [(match_dup 9) (match_dup 5)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 11) - (unspec:XF [(match_dup 9) (match_dup 5)] - UNSPEC_FSCALE_EXP))]) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 10)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx temp; - int i; - - for (i=2; i<12; i++) - operands[i] = gen_reg_rtx (XFmode); - temp = standard_80387_constant_rtx (6); /* fldl2t */ emit_move_insn (operands[3], temp); emit_move_insn (operands[8], CONST1_RTX (XFmode)); /* fld1 */ }) -(define_expand "exp10df2" - [(set (match_dup 2) - (float_extend:XF (match_operand:DF 1 "register_operand" ""))) - (set (match_dup 4) (mult:XF (match_dup 2) (match_dup 3))) - (set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_FRNDINT)) - (set (match_dup 6) (minus:XF (match_dup 4) (match_dup 5))) - (set (match_dup 7) (unspec:XF [(match_dup 6)] UNSPEC_F2XM1)) - (set (match_dup 9) (plus:XF (match_dup 7) (match_dup 8))) - (parallel [(set (match_dup 10) - (unspec:XF [(match_dup 9) (match_dup 5)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 11) - (unspec:XF [(match_dup 9) (match_dup 5)] - UNSPEC_FSCALE_EXP))]) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 10)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx temp; - int i; - - for (i=2; i<12; i++) - operands[i] = gen_reg_rtx (XFmode); - temp = standard_80387_constant_rtx (6); /* fldl2t */ - emit_move_insn (operands[3], temp); - emit_move_insn (operands[8], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "exp10xf2" +(define_expand "expxf2" [(set (match_dup 3) (mult:XF (match_operand:XF 1 "register_operand" "") (match_dup 2))) (set (match_dup 4) (unspec:XF [(match_dup 3)] UNSPEC_FRNDINT)) @@ -16874,1145 +15320,89 @@ (set (match_dup 6) (unspec:XF [(match_dup 5)] UNSPEC_F2XM1)) (set (match_dup 8) (plus:XF (match_dup 6) (match_dup 7))) (parallel [(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_dup 8) (match_dup 4)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 9) - (unspec:XF [(match_dup 8) (match_dup 4)] - UNSPEC_FSCALE_EXP))])] - "TARGET_USE_FANCY_MATH_387 + (unspec:XF [(match_dup 8) (match_dup 4)] UNSPEC_FSCALE)) + (clobber (match_scratch:XF 5 ""))])] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { rtx temp; int i; - for (i=2; i<10; i++) - operands[i] = gen_reg_rtx (XFmode); - temp = standard_80387_constant_rtx (6); /* fldl2t */ - emit_move_insn (operands[2], temp); - emit_move_insn (operands[7], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "exp2sf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:SF 1 "register_operand" ""))) - (set (match_dup 3) (unspec:XF [(match_dup 2)] UNSPEC_FRNDINT)) - (set (match_dup 4) (minus:XF (match_dup 2) (match_dup 3))) - (set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_F2XM1)) - (set (match_dup 7) (plus:XF (match_dup 5) (match_dup 6))) - (parallel [(set (match_dup 8) - (unspec:XF [(match_dup 7) (match_dup 3)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 9) - (unspec:XF [(match_dup 7) (match_dup 3)] - UNSPEC_FSCALE_EXP))]) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 8)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - int i; - - for (i=2; i<10; i++) - operands[i] = gen_reg_rtx (XFmode); - emit_move_insn (operands[6], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "exp2df2" - [(set (match_dup 2) - (float_extend:XF (match_operand:DF 1 "register_operand" ""))) - (set (match_dup 3) (unspec:XF [(match_dup 2)] UNSPEC_FRNDINT)) - (set (match_dup 4) (minus:XF (match_dup 2) (match_dup 3))) - (set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_F2XM1)) - (set (match_dup 7) (plus:XF (match_dup 5) (match_dup 6))) - (parallel [(set (match_dup 8) - (unspec:XF [(match_dup 7) (match_dup 3)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 9) - (unspec:XF [(match_dup 7) (match_dup 3)] - UNSPEC_FSCALE_EXP))]) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 8)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - int i; - - for (i=2; i<10; i++) - operands[i] = gen_reg_rtx (XFmode); - emit_move_insn (operands[6], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "exp2xf2" - [(set (match_dup 2) (match_operand:XF 1 "register_operand" "")) - (set (match_dup 3) (unspec:XF [(match_dup 2)] UNSPEC_FRNDINT)) - (set (match_dup 4) (minus:XF (match_dup 2) (match_dup 3))) - (set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_F2XM1)) - (set (match_dup 7) (plus:XF (match_dup 5) (match_dup 6))) - (parallel [(set (match_operand:XF 0 "register_operand" "") - (unspec:XF [(match_dup 7) (match_dup 3)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 8) - (unspec:XF [(match_dup 7) (match_dup 3)] - UNSPEC_FSCALE_EXP))])] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - int i; - for (i=2; i<9; i++) operands[i] = gen_reg_rtx (XFmode); - emit_move_insn (operands[6], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "expm1df2" - [(set (match_dup 2) - (float_extend:XF (match_operand:DF 1 "register_operand" ""))) - (set (match_dup 4) (mult:XF (match_dup 2) (match_dup 3))) - (set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_FRNDINT)) - (set (match_dup 6) (minus:XF (match_dup 4) (match_dup 5))) - (set (match_dup 7) (unspec:XF [(match_dup 6)] UNSPEC_F2XM1)) - (parallel [(set (match_dup 8) - (unspec:XF [(match_dup 7) (match_dup 5)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 9) - (unspec:XF [(match_dup 7) (match_dup 5)] - UNSPEC_FSCALE_EXP))]) - (parallel [(set (match_dup 11) - (unspec:XF [(match_dup 10) (match_dup 9)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 12) - (unspec:XF [(match_dup 10) (match_dup 9)] - UNSPEC_FSCALE_EXP))]) - (set (match_dup 13) (minus:XF (match_dup 11) (match_dup 10))) - (set (match_dup 14) (plus:XF (match_dup 13) (match_dup 8))) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 14)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx temp; - int i; - - for (i=2; i<15; i++) - operands[i] = gen_reg_rtx (XFmode); - temp = standard_80387_constant_rtx (5); /* fldl2e */ - emit_move_insn (operands[3], temp); - emit_move_insn (operands[10], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "expm1sf2" - [(set (match_dup 2) - (float_extend:XF (match_operand:SF 1 "register_operand" ""))) - (set (match_dup 4) (mult:XF (match_dup 2) (match_dup 3))) - (set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_FRNDINT)) - (set (match_dup 6) (minus:XF (match_dup 4) (match_dup 5))) - (set (match_dup 7) (unspec:XF [(match_dup 6)] UNSPEC_F2XM1)) - (parallel [(set (match_dup 8) - (unspec:XF [(match_dup 7) (match_dup 5)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 9) - (unspec:XF [(match_dup 7) (match_dup 5)] - UNSPEC_FSCALE_EXP))]) - (parallel [(set (match_dup 11) - (unspec:XF [(match_dup 10) (match_dup 9)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 12) - (unspec:XF [(match_dup 10) (match_dup 9)] - UNSPEC_FSCALE_EXP))]) - (set (match_dup 13) (minus:XF (match_dup 11) (match_dup 10))) - (set (match_dup 14) (plus:XF (match_dup 13) (match_dup 8))) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 14)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx temp; - int i; - - for (i=2; i<15; i++) - operands[i] = gen_reg_rtx (XFmode); - temp = standard_80387_constant_rtx (5); /* fldl2e */ - emit_move_insn (operands[3], temp); - emit_move_insn (operands[10], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "expm1xf2" - [(set (match_dup 3) (mult:XF (match_operand:XF 1 "register_operand" "") - (match_dup 2))) - (set (match_dup 4) (unspec:XF [(match_dup 3)] UNSPEC_FRNDINT)) - (set (match_dup 5) (minus:XF (match_dup 3) (match_dup 4))) - (set (match_dup 6) (unspec:XF [(match_dup 5)] UNSPEC_F2XM1)) - (parallel [(set (match_dup 7) - (unspec:XF [(match_dup 6) (match_dup 4)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 8) - (unspec:XF [(match_dup 6) (match_dup 4)] - UNSPEC_FSCALE_EXP))]) - (parallel [(set (match_dup 10) - (unspec:XF [(match_dup 9) (match_dup 8)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 11) - (unspec:XF [(match_dup 9) (match_dup 8)] - UNSPEC_FSCALE_EXP))]) - (set (match_dup 12) (minus:XF (match_dup 10) (match_dup 9))) - (set (match_operand:XF 0 "register_operand" "") - (plus:XF (match_dup 12) (match_dup 7)))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - rtx temp; - int i; - - for (i=2; i<13; i++) - operands[i] = gen_reg_rtx (XFmode); temp = standard_80387_constant_rtx (5); /* fldl2e */ emit_move_insn (operands[2], temp); - emit_move_insn (operands[9], CONST1_RTX (XFmode)); /* fld1 */ -}) - -(define_expand "ldexpdf3" - [(set (match_dup 3) - (float_extend:XF (match_operand:DF 1 "register_operand" ""))) - (set (match_dup 4) - (float:XF (match_operand:SI 2 "register_operand" ""))) - (parallel [(set (match_dup 5) - (unspec:XF [(match_dup 3) (match_dup 4)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 6) - (unspec:XF [(match_dup 3) (match_dup 4)] - UNSPEC_FSCALE_EXP))]) - (set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_dup 5)))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - int i; - - for (i=3; i<7; i++) - operands[i] = gen_reg_rtx (XFmode); -}) - -(define_expand "ldexpsf3" - [(set (match_dup 3) - (float_extend:XF (match_operand:SF 1 "register_operand" ""))) - (set (match_dup 4) - (float:XF (match_operand:SI 2 "register_operand" ""))) - (parallel [(set (match_dup 5) - (unspec:XF [(match_dup 3) (match_dup 4)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 6) - (unspec:XF [(match_dup 3) (match_dup 4)] - UNSPEC_FSCALE_EXP))]) - (set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_dup 5)))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - int i; - - for (i=3; i<7; i++) - operands[i] = gen_reg_rtx (XFmode); -}) - -(define_expand "ldexpxf3" - [(set (match_dup 3) - (float:XF (match_operand:SI 2 "register_operand" ""))) - (parallel [(set (match_operand:XF 0 " register_operand" "") - (unspec:XF [(match_operand:XF 1 "register_operand" "") - (match_dup 3)] - UNSPEC_FSCALE_FRACT)) - (set (match_dup 4) - (unspec:XF [(match_dup 1) (match_dup 3)] - UNSPEC_FSCALE_EXP))])] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - int i; - - for (i=3; i<5; i++) - operands[i] = gen_reg_rtx (XFmode); -}) - - -(define_insn "frndintxf2" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 1 "register_operand" "0")] - UNSPEC_FRNDINT))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "frndint" - [(set_attr "type" "fpspc") - (set_attr "mode" "XF")]) - -(define_expand "rintdf2" - [(use (match_operand:DF 0 "register_operand" "")) - (use (match_operand:DF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extenddfxf2 (op1, operands[1])); - emit_insn (gen_frndintxf2 (op0, op1)); - - emit_insn (gen_truncxfdf2_i387_noop (operands[0], op0)); - DONE; -}) - -(define_expand "rintsf2" - [(use (match_operand:SF 0 "register_operand" "")) - (use (match_operand:SF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extendsfxf2 (op1, operands[1])); - emit_insn (gen_frndintxf2 (op0, op1)); - - emit_insn (gen_truncxfsf2_i387_noop (operands[0], op0)); - DONE; -}) - -(define_expand "rintxf2" - [(use (match_operand:XF 0 "register_operand" "")) - (use (match_operand:XF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - emit_insn (gen_frndintxf2 (operands[0], operands[1])); - DONE; -}) - -(define_insn_and_split "*fistdi2_1" - [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r") - (unspec:DI [(match_operand:XF 1 "register_operand" "f,f")] - UNSPEC_FIST))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations - && !(reload_completed || reload_in_progress)" - "#" - "&& 1" - [(const_int 0)] -{ - if (memory_operand (operands[0], VOIDmode)) - emit_insn (gen_fistdi2 (operands[0], operands[1])); - else - { - operands[2] = assign_386_stack_local (DImode, SLOT_TEMP); - emit_insn (gen_fistdi2_with_temp (operands[0], operands[1], - operands[2])); - } - DONE; -} - [(set_attr "type" "fpspc") - (set_attr "mode" "DI")]) - -(define_insn "fistdi2" - [(set (match_operand:DI 0 "memory_operand" "=m") - (unspec:DI [(match_operand:XF 1 "register_operand" "f")] - UNSPEC_FIST)) - (clobber (match_scratch:XF 2 "=&1f"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "* return output_fix_trunc (insn, operands, 0);" - [(set_attr "type" "fpspc") - (set_attr "mode" "DI")]) - -(define_insn "fistdi2_with_temp" - [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r") - (unspec:DI [(match_operand:XF 1 "register_operand" "f,f")] - UNSPEC_FIST)) - (clobber (match_operand:DI 2 "memory_operand" "=m,m")) - (clobber (match_scratch:XF 3 "=&1f,&1f"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "#" - [(set_attr "type" "fpspc") - (set_attr "mode" "DI")]) - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (unspec:DI [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST)) - (clobber (match_operand:DI 2 "memory_operand" "")) - (clobber (match_scratch 3 ""))] - "reload_completed" - [(parallel [(set (match_dup 2) (unspec:DI [(match_dup 1)] UNSPEC_FIST)) - (clobber (match_dup 3))]) - (set (match_dup 0) (match_dup 2))] - "") - -(define_split - [(set (match_operand:DI 0 "memory_operand" "") - (unspec:DI [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST)) - (clobber (match_operand:DI 2 "memory_operand" "")) - (clobber (match_scratch 3 ""))] - "reload_completed" - [(parallel [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_FIST)) - (clobber (match_dup 3))])] - "") - -(define_insn_and_split "*fist<mode>2_1" - [(set (match_operand:X87MODEI12 0 "register_operand" "=r") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")] - UNSPEC_FIST))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations - && !(reload_completed || reload_in_progress)" - "#" - "&& 1" - [(const_int 0)] -{ - operands[2] = assign_386_stack_local (<MODE>mode, SLOT_TEMP); - emit_insn (gen_fist<mode>2_with_temp (operands[0], operands[1], - operands[2])); - DONE; -} - [(set_attr "type" "fpspc") - (set_attr "mode" "<MODE>")]) - -(define_insn "fist<mode>2" - [(set (match_operand:X87MODEI12 0 "memory_operand" "=m") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")] - UNSPEC_FIST))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "* return output_fix_trunc (insn, operands, 0);" - [(set_attr "type" "fpspc") - (set_attr "mode" "<MODE>")]) - -(define_insn "fist<mode>2_with_temp" - [(set (match_operand:X87MODEI12 0 "register_operand" "=r") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")] - UNSPEC_FIST)) - (clobber (match_operand:X87MODEI12 2 "memory_operand" "=m"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "#" - [(set_attr "type" "fpspc") - (set_attr "mode" "<MODE>")]) - -(define_split - [(set (match_operand:X87MODEI12 0 "register_operand" "") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST)) - (clobber (match_operand:X87MODEI12 2 "memory_operand" ""))] - "reload_completed" - [(set (match_dup 2) (unspec:X87MODEI12 [(match_dup 1)] - UNSPEC_FIST)) - (set (match_dup 0) (match_dup 2))] - "") - -(define_split - [(set (match_operand:X87MODEI12 0 "memory_operand" "") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST)) - (clobber (match_operand:X87MODEI12 2 "memory_operand" ""))] - "reload_completed" - [(set (match_dup 0) (unspec:X87MODEI12 [(match_dup 1)] - UNSPEC_FIST))] - "") - -(define_expand "lrint<mode>2" - [(set (match_operand:X87MODEI 0 "nonimmediate_operand" "") - (unspec:X87MODEI [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" - "") - -;; Rounding mode control word calculation could clobber FLAGS_REG. -(define_insn_and_split "frndintxf2_floor" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 1 "register_operand" "0")] - UNSPEC_FRNDINT_FLOOR)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations - && !(reload_completed || reload_in_progress)" - "#" - "&& 1" - [(const_int 0)] -{ - ix86_optimize_mode_switching[I387_FLOOR] = 1; - - operands[2] = assign_386_stack_local (HImode, SLOT_CW_STORED); - operands[3] = assign_386_stack_local (HImode, SLOT_CW_FLOOR); - - emit_insn (gen_frndintxf2_floor_i387 (operands[0], operands[1], - operands[2], operands[3])); - DONE; -} - [(set_attr "type" "frndint") - (set_attr "i387_cw" "floor") - (set_attr "mode" "XF")]) - -(define_insn "frndintxf2_floor_i387" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 1 "register_operand" "0")] - UNSPEC_FRNDINT_FLOOR)) - (use (match_operand:HI 2 "memory_operand" "m")) - (use (match_operand:HI 3 "memory_operand" "m"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "fldcw\t%3\n\tfrndint\n\tfldcw\t%2" - [(set_attr "type" "frndint") - (set_attr "i387_cw" "floor") - (set_attr "mode" "XF")]) - -(define_expand "floorxf2" - [(use (match_operand:XF 0 "register_operand" "")) - (use (match_operand:XF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - emit_insn (gen_frndintxf2_floor (operands[0], operands[1])); - DONE; -}) - -(define_expand "floordf2" - [(use (match_operand:DF 0 "register_operand" "")) - (use (match_operand:DF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extenddfxf2 (op1, operands[1])); - emit_insn (gen_frndintxf2_floor (op0, op1)); - - emit_insn (gen_truncxfdf2_i387_noop (operands[0], op0)); - DONE; -}) - -(define_expand "floorsf2" - [(use (match_operand:SF 0 "register_operand" "")) - (use (match_operand:SF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extendsfxf2 (op1, operands[1])); - emit_insn (gen_frndintxf2_floor (op0, op1)); - - emit_insn (gen_truncxfsf2_i387_noop (operands[0], op0)); - DONE; -}) - -(define_insn_and_split "*fist<mode>2_floor_1" - [(set (match_operand:X87MODEI 0 "nonimmediate_operand" "=m,?r") - (unspec:X87MODEI [(match_operand:XF 1 "register_operand" "f,f")] - UNSPEC_FIST_FLOOR)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations - && !(reload_completed || reload_in_progress)" - "#" - "&& 1" - [(const_int 0)] -{ - ix86_optimize_mode_switching[I387_FLOOR] = 1; - - operands[2] = assign_386_stack_local (HImode, SLOT_CW_STORED); - operands[3] = assign_386_stack_local (HImode, SLOT_CW_FLOOR); - if (memory_operand (operands[0], VOIDmode)) - emit_insn (gen_fist<mode>2_floor (operands[0], operands[1], - operands[2], operands[3])); - else - { - operands[4] = assign_386_stack_local (<MODE>mode, SLOT_TEMP); - emit_insn (gen_fist<mode>2_floor_with_temp (operands[0], operands[1], - operands[2], operands[3], - operands[4])); - } - DONE; -} - [(set_attr "type" "fistp") - (set_attr "i387_cw" "floor") - (set_attr "mode" "<MODE>")]) - -(define_insn "fistdi2_floor" - [(set (match_operand:DI 0 "memory_operand" "=m") - (unspec:DI [(match_operand:XF 1 "register_operand" "f")] - UNSPEC_FIST_FLOOR)) - (use (match_operand:HI 2 "memory_operand" "m")) - (use (match_operand:HI 3 "memory_operand" "m")) - (clobber (match_scratch:XF 4 "=&1f"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "* return output_fix_trunc (insn, operands, 0);" - [(set_attr "type" "fistp") - (set_attr "i387_cw" "floor") - (set_attr "mode" "DI")]) - -(define_insn "fistdi2_floor_with_temp" - [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r") - (unspec:DI [(match_operand:XF 1 "register_operand" "f,f")] - UNSPEC_FIST_FLOOR)) - (use (match_operand:HI 2 "memory_operand" "m,m")) - (use (match_operand:HI 3 "memory_operand" "m,m")) - (clobber (match_operand:DI 4 "memory_operand" "=m,m")) - (clobber (match_scratch:XF 5 "=&1f,&1f"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "#" - [(set_attr "type" "fistp") - (set_attr "i387_cw" "floor") - (set_attr "mode" "DI")]) - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (unspec:DI [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST_FLOOR)) - (use (match_operand:HI 2 "memory_operand" "")) - (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:DI 4 "memory_operand" "")) - (clobber (match_scratch 5 ""))] - "reload_completed" - [(parallel [(set (match_dup 4) (unspec:DI [(match_dup 1)] UNSPEC_FIST_FLOOR)) - (use (match_dup 2)) - (use (match_dup 3)) - (clobber (match_dup 5))]) - (set (match_dup 0) (match_dup 4))] - "") - -(define_split - [(set (match_operand:DI 0 "memory_operand" "") - (unspec:DI [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST_FLOOR)) - (use (match_operand:HI 2 "memory_operand" "")) - (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:DI 4 "memory_operand" "")) - (clobber (match_scratch 5 ""))] - "reload_completed" - [(parallel [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_FIST_FLOOR)) - (use (match_dup 2)) - (use (match_dup 3)) - (clobber (match_dup 5))])] - "") - -(define_insn "fist<mode>2_floor" - [(set (match_operand:X87MODEI12 0 "memory_operand" "=m") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")] - UNSPEC_FIST_FLOOR)) - (use (match_operand:HI 2 "memory_operand" "m")) - (use (match_operand:HI 3 "memory_operand" "m"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "* return output_fix_trunc (insn, operands, 0);" - [(set_attr "type" "fistp") - (set_attr "i387_cw" "floor") - (set_attr "mode" "<MODE>")]) - -(define_insn "fist<mode>2_floor_with_temp" - [(set (match_operand:X87MODEI12 0 "nonimmediate_operand" "=m,?r") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f,f")] - UNSPEC_FIST_FLOOR)) - (use (match_operand:HI 2 "memory_operand" "m,m")) - (use (match_operand:HI 3 "memory_operand" "m,m")) - (clobber (match_operand:X87MODEI12 4 "memory_operand" "=m,m"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "#" - [(set_attr "type" "fistp") - (set_attr "i387_cw" "floor") - (set_attr "mode" "<MODE>")]) - -(define_split - [(set (match_operand:X87MODEI12 0 "register_operand" "") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST_FLOOR)) - (use (match_operand:HI 2 "memory_operand" "")) - (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:X87MODEI12 4 "memory_operand" ""))] - "reload_completed" - [(parallel [(set (match_dup 4) (unspec:X87MODEI12 [(match_dup 1)] - UNSPEC_FIST_FLOOR)) - (use (match_dup 2)) - (use (match_dup 3))]) - (set (match_dup 0) (match_dup 4))] - "") - -(define_split - [(set (match_operand:X87MODEI12 0 "memory_operand" "") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST_FLOOR)) - (use (match_operand:HI 2 "memory_operand" "")) - (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:X87MODEI12 4 "memory_operand" ""))] - "reload_completed" - [(parallel [(set (match_dup 0) (unspec:X87MODEI12 [(match_dup 1)] - UNSPEC_FIST_FLOOR)) - (use (match_dup 2)) - (use (match_dup 3))])] - "") - -(define_expand "lfloor<mode>2" - [(parallel [(set (match_operand:X87MODEI 0 "nonimmediate_operand" "") - (unspec:X87MODEI [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST_FLOOR)) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" - "") - -;; Rounding mode control word calculation could clobber FLAGS_REG. -(define_insn_and_split "frndintxf2_ceil" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 1 "register_operand" "0")] - UNSPEC_FRNDINT_CEIL)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations - && !(reload_completed || reload_in_progress)" - "#" - "&& 1" - [(const_int 0)] -{ - ix86_optimize_mode_switching[I387_CEIL] = 1; - - operands[2] = assign_386_stack_local (HImode, SLOT_CW_STORED); - operands[3] = assign_386_stack_local (HImode, SLOT_CW_CEIL); - - emit_insn (gen_frndintxf2_ceil_i387 (operands[0], operands[1], - operands[2], operands[3])); - DONE; -} - [(set_attr "type" "frndint") - (set_attr "i387_cw" "ceil") - (set_attr "mode" "XF")]) - -(define_insn "frndintxf2_ceil_i387" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 1 "register_operand" "0")] - UNSPEC_FRNDINT_CEIL)) - (use (match_operand:HI 2 "memory_operand" "m")) - (use (match_operand:HI 3 "memory_operand" "m"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "fldcw\t%3\n\tfrndint\n\tfldcw\t%2" - [(set_attr "type" "frndint") - (set_attr "i387_cw" "ceil") - (set_attr "mode" "XF")]) - -(define_expand "ceilxf2" - [(use (match_operand:XF 0 "register_operand" "")) - (use (match_operand:XF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - emit_insn (gen_frndintxf2_ceil (operands[0], operands[1])); - DONE; -}) - -(define_expand "ceildf2" - [(use (match_operand:DF 0 "register_operand" "")) - (use (match_operand:DF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extenddfxf2 (op1, operands[1])); - emit_insn (gen_frndintxf2_ceil (op0, op1)); - - emit_insn (gen_truncxfdf2_i387_noop (operands[0], op0)); - DONE; -}) - -(define_expand "ceilsf2" - [(use (match_operand:SF 0 "register_operand" "")) - (use (match_operand:SF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extendsfxf2 (op1, operands[1])); - emit_insn (gen_frndintxf2_ceil (op0, op1)); - - emit_insn (gen_truncxfsf2_i387_noop (operands[0], op0)); - DONE; -}) - -(define_insn_and_split "*fist<mode>2_ceil_1" - [(set (match_operand:X87MODEI 0 "nonimmediate_operand" "=m,?r") - (unspec:X87MODEI [(match_operand:XF 1 "register_operand" "f,f")] - UNSPEC_FIST_CEIL)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations - && !(reload_completed || reload_in_progress)" - "#" - "&& 1" - [(const_int 0)] -{ - ix86_optimize_mode_switching[I387_CEIL] = 1; - - operands[2] = assign_386_stack_local (HImode, SLOT_CW_STORED); - operands[3] = assign_386_stack_local (HImode, SLOT_CW_CEIL); - if (memory_operand (operands[0], VOIDmode)) - emit_insn (gen_fist<mode>2_ceil (operands[0], operands[1], - operands[2], operands[3])); - else - { - operands[4] = assign_386_stack_local (<MODE>mode, SLOT_TEMP); - emit_insn (gen_fist<mode>2_ceil_with_temp (operands[0], operands[1], - operands[2], operands[3], - operands[4])); - } - DONE; -} - [(set_attr "type" "fistp") - (set_attr "i387_cw" "ceil") - (set_attr "mode" "<MODE>")]) - -(define_insn "fistdi2_ceil" - [(set (match_operand:DI 0 "memory_operand" "=m") - (unspec:DI [(match_operand:XF 1 "register_operand" "f")] - UNSPEC_FIST_CEIL)) - (use (match_operand:HI 2 "memory_operand" "m")) - (use (match_operand:HI 3 "memory_operand" "m")) - (clobber (match_scratch:XF 4 "=&1f"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "* return output_fix_trunc (insn, operands, 0);" - [(set_attr "type" "fistp") - (set_attr "i387_cw" "ceil") - (set_attr "mode" "DI")]) - -(define_insn "fistdi2_ceil_with_temp" - [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r") - (unspec:DI [(match_operand:XF 1 "register_operand" "f,f")] - UNSPEC_FIST_CEIL)) - (use (match_operand:HI 2 "memory_operand" "m,m")) - (use (match_operand:HI 3 "memory_operand" "m,m")) - (clobber (match_operand:DI 4 "memory_operand" "=m,m")) - (clobber (match_scratch:XF 5 "=&1f,&1f"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "#" - [(set_attr "type" "fistp") - (set_attr "i387_cw" "ceil") - (set_attr "mode" "DI")]) - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (unspec:DI [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST_CEIL)) - (use (match_operand:HI 2 "memory_operand" "")) - (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:DI 4 "memory_operand" "")) - (clobber (match_scratch 5 ""))] - "reload_completed" - [(parallel [(set (match_dup 4) (unspec:DI [(match_dup 1)] UNSPEC_FIST_CEIL)) - (use (match_dup 2)) - (use (match_dup 3)) - (clobber (match_dup 5))]) - (set (match_dup 0) (match_dup 4))] - "") - -(define_split - [(set (match_operand:DI 0 "memory_operand" "") - (unspec:DI [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST_CEIL)) - (use (match_operand:HI 2 "memory_operand" "")) - (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:DI 4 "memory_operand" "")) - (clobber (match_scratch 5 ""))] - "reload_completed" - [(parallel [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_FIST_CEIL)) - (use (match_dup 2)) - (use (match_dup 3)) - (clobber (match_dup 5))])] - "") - -(define_insn "fist<mode>2_ceil" - [(set (match_operand:X87MODEI12 0 "memory_operand" "=m") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")] - UNSPEC_FIST_CEIL)) - (use (match_operand:HI 2 "memory_operand" "m")) - (use (match_operand:HI 3 "memory_operand" "m"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "* return output_fix_trunc (insn, operands, 0);" - [(set_attr "type" "fistp") - (set_attr "i387_cw" "ceil") - (set_attr "mode" "<MODE>")]) - -(define_insn "fist<mode>2_ceil_with_temp" - [(set (match_operand:X87MODEI12 0 "nonimmediate_operand" "=m,?r") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f,f")] - UNSPEC_FIST_CEIL)) - (use (match_operand:HI 2 "memory_operand" "m,m")) - (use (match_operand:HI 3 "memory_operand" "m,m")) - (clobber (match_operand:X87MODEI12 4 "memory_operand" "=m,m"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "#" - [(set_attr "type" "fistp") - (set_attr "i387_cw" "ceil") - (set_attr "mode" "<MODE>")]) - -(define_split - [(set (match_operand:X87MODEI12 0 "register_operand" "") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST_CEIL)) - (use (match_operand:HI 2 "memory_operand" "")) - (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:X87MODEI12 4 "memory_operand" ""))] - "reload_completed" - [(parallel [(set (match_dup 4) (unspec:X87MODEI12 [(match_dup 1)] - UNSPEC_FIST_CEIL)) - (use (match_dup 2)) - (use (match_dup 3))]) - (set (match_dup 0) (match_dup 4))] - "") - -(define_split - [(set (match_operand:X87MODEI12 0 "memory_operand" "") - (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST_CEIL)) - (use (match_operand:HI 2 "memory_operand" "")) - (use (match_operand:HI 3 "memory_operand" "")) - (clobber (match_operand:X87MODEI12 4 "memory_operand" ""))] - "reload_completed" - [(parallel [(set (match_dup 0) (unspec:X87MODEI12 [(match_dup 1)] - UNSPEC_FIST_CEIL)) - (use (match_dup 2)) - (use (match_dup 3))])] - "") - -(define_expand "lceil<mode>2" - [(parallel [(set (match_operand:X87MODEI 0 "nonimmediate_operand" "") - (unspec:X87MODEI [(match_operand:XF 1 "register_operand" "")] - UNSPEC_FIST_CEIL)) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" - "") - -;; Rounding mode control word calculation could clobber FLAGS_REG. -(define_insn_and_split "frndintxf2_trunc" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 1 "register_operand" "0")] - UNSPEC_FRNDINT_TRUNC)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations - && !(reload_completed || reload_in_progress)" - "#" - "&& 1" - [(const_int 0)] -{ - ix86_optimize_mode_switching[I387_TRUNC] = 1; - - operands[2] = assign_386_stack_local (HImode, SLOT_CW_STORED); - operands[3] = assign_386_stack_local (HImode, SLOT_CW_TRUNC); - - emit_insn (gen_frndintxf2_trunc_i387 (operands[0], operands[1], - operands[2], operands[3])); - DONE; -} - [(set_attr "type" "frndint") - (set_attr "i387_cw" "trunc") - (set_attr "mode" "XF")]) - -(define_insn "frndintxf2_trunc_i387" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 1 "register_operand" "0")] - UNSPEC_FRNDINT_TRUNC)) - (use (match_operand:HI 2 "memory_operand" "m")) - (use (match_operand:HI 3 "memory_operand" "m"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "fldcw\t%3\n\tfrndint\n\tfldcw\t%2" - [(set_attr "type" "frndint") - (set_attr "i387_cw" "trunc") - (set_attr "mode" "XF")]) - -(define_expand "btruncxf2" - [(use (match_operand:XF 0 "register_operand" "")) - (use (match_operand:XF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" -{ - emit_insn (gen_frndintxf2_trunc (operands[0], operands[1])); - DONE; -}) - -(define_expand "btruncdf2" - [(use (match_operand:DF 0 "register_operand" "")) - (use (match_operand:DF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extenddfxf2 (op1, operands[1])); - emit_insn (gen_frndintxf2_trunc (op0, op1)); - - emit_insn (gen_truncxfdf2_i387_noop (operands[0], op0)); - DONE; -}) - -(define_expand "btruncsf2" - [(use (match_operand:SF 0 "register_operand" "")) - (use (match_operand:SF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) - && flag_unsafe_math_optimizations" -{ - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extendsfxf2 (op1, operands[1])); - emit_insn (gen_frndintxf2_trunc (op0, op1)); - - emit_insn (gen_truncxfsf2_i387_noop (operands[0], op0)); - DONE; + emit_move_insn (operands[7], CONST1_RTX (XFmode)); /* fld1 */ }) -;; Rounding mode control word calculation could clobber FLAGS_REG. -(define_insn_and_split "frndintxf2_mask_pm" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 1 "register_operand" "0")] - UNSPEC_FRNDINT_MASK_PM)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations - && !(reload_completed || reload_in_progress)" - "#" - "&& 1" - [(const_int 0)] -{ - ix86_optimize_mode_switching[I387_MASK_PM] = 1; - - operands[2] = assign_386_stack_local (HImode, SLOT_CW_STORED); - operands[3] = assign_386_stack_local (HImode, SLOT_CW_MASK_PM); - - emit_insn (gen_frndintxf2_mask_pm_i387 (operands[0], operands[1], - operands[2], operands[3])); - DONE; -} - [(set_attr "type" "frndint") - (set_attr "i387_cw" "mask_pm") - (set_attr "mode" "XF")]) - -(define_insn "frndintxf2_mask_pm_i387" - [(set (match_operand:XF 0 "register_operand" "=f") - (unspec:XF [(match_operand:XF 1 "register_operand" "0")] - UNSPEC_FRNDINT_MASK_PM)) - (use (match_operand:HI 2 "memory_operand" "m")) - (use (match_operand:HI 3 "memory_operand" "m"))] - "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations" - "fldcw\t%3\n\tfrndint\n\tfclex\n\tfldcw\t%2" - [(set_attr "type" "frndint") - (set_attr "i387_cw" "mask_pm") - (set_attr "mode" "XF")]) - -(define_expand "nearbyintxf2" - [(use (match_operand:XF 0 "register_operand" "")) - (use (match_operand:XF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 +(define_expand "atansf2" + [(parallel [(set (match_operand:SF 0 "register_operand" "") + (unspec:SF [(match_dup 2) + (match_operand:SF 1 "register_operand" "")] + UNSPEC_FPATAN)) + (clobber (match_scratch:SF 3 ""))])] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { - emit_insn (gen_frndintxf2_mask_pm (operands[0], operands[1])); - - DONE; + operands[2] = gen_reg_rtx (SFmode); + emit_move_insn (operands[2], CONST1_RTX (SFmode)); /* fld1 */ }) -(define_expand "nearbyintdf2" - [(use (match_operand:DF 0 "register_operand" "")) - (use (match_operand:DF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!(TARGET_SSE2 && TARGET_SSE_MATH) || TARGET_MIX_SSE_I387) +(define_expand "atandf2" + [(parallel [(set (match_operand:DF 0 "register_operand" "") + (unspec:DF [(match_dup 2) + (match_operand:DF 1 "register_operand" "")] + UNSPEC_FPATAN)) + (clobber (match_scratch:DF 3 ""))])] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extenddfxf2 (op1, operands[1])); - emit_insn (gen_frndintxf2_mask_pm (op0, op1)); - - emit_insn (gen_truncxfdf2_i387_noop (operands[0], op0)); - DONE; + operands[2] = gen_reg_rtx (DFmode); + emit_move_insn (operands[2], CONST1_RTX (DFmode)); /* fld1 */ }) -(define_expand "nearbyintsf2" - [(use (match_operand:SF 0 "register_operand" "")) - (use (match_operand:SF 1 "register_operand" ""))] - "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) +(define_expand "atanxf2" + [(parallel [(set (match_operand:XF 0 "register_operand" "") + (unspec:XF [(match_dup 2) + (match_operand:XF 1 "register_operand" "")] + UNSPEC_FPATAN)) + (clobber (match_scratch:XF 3 ""))])] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_unsafe_math_optimizations" { - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); - - emit_insn (gen_extendsfxf2 (op1, operands[1])); - emit_insn (gen_frndintxf2_mask_pm (op0, op1)); - - emit_insn (gen_truncxfsf2_i387_noop (operands[0], op0)); - DONE; + operands[2] = gen_reg_rtx (XFmode); + emit_move_insn (operands[2], CONST1_RTX (XFmode)); /* fld1 */ }) - ;; Block operation instructions (define_insn "cld" - [(set (reg:SI DIRFLAG_REG) (const_int 0))] + [(set (reg:SI 19) (const_int 0))] "" "cld" [(set_attr "type" "cld")]) -(define_expand "movmemsi" +(define_expand "movstrsi" [(use (match_operand:BLK 0 "memory_operand" "")) (use (match_operand:BLK 1 "memory_operand" "")) (use (match_operand:SI 2 "nonmemory_operand" "")) (use (match_operand:SI 3 "const_int_operand" ""))] - "! optimize_size || TARGET_INLINE_ALL_STRINGOPS" + "! optimize_size" { - if (ix86_expand_movmem (operands[0], operands[1], operands[2], operands[3])) + if (ix86_expand_movstr (operands[0], operands[1], operands[2], operands[3])) DONE; else FAIL; }) -(define_expand "movmemdi" +(define_expand "movstrdi" [(use (match_operand:BLK 0 "memory_operand" "")) (use (match_operand:BLK 1 "memory_operand" "")) (use (match_operand:DI 2 "nonmemory_operand" "")) (use (match_operand:DI 3 "const_int_operand" ""))] "TARGET_64BIT" { - if (ix86_expand_movmem (operands[0], operands[1], operands[2], operands[3])) + if (ix86_expand_movstr (operands[0], operands[1], operands[2], operands[3])) DONE; else FAIL; @@ -18025,9 +15415,9 @@ [(set (match_dup 4) (match_operand 3 "memory_operand" "")) (set (match_operand 1 "memory_operand" "") (match_dup 4)) (parallel [(set (match_operand 0 "register_operand" "") (match_dup 5)) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (parallel [(set (match_operand 2 "register_operand" "") (match_dup 6)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" { rtx adjust = GEN_INT (GET_MODE_SIZE (GET_MODE (operands[1]))); @@ -18055,7 +15445,7 @@ (match_operand 4 "" "")) (set (match_operand 2 "register_operand" "") (match_operand 5 "" "")) - (use (reg:SI DIRFLAG_REG))])] + (use (reg:SI 19))])] "TARGET_SINGLE_STRINGOP || optimize_size" "") @@ -18068,7 +15458,7 @@ (set (match_operand:DI 1 "register_operand" "=S") (plus:DI (match_dup 3) (const_int 8))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "movsq" [(set_attr "type" "str") @@ -18084,7 +15474,7 @@ (set (match_operand:SI 1 "register_operand" "=S") (plus:SI (match_dup 3) (const_int 4))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "{movsl|movsd}" [(set_attr "type" "str") @@ -18100,7 +15490,7 @@ (set (match_operand:DI 1 "register_operand" "=S") (plus:DI (match_dup 3) (const_int 4))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "{movsl|movsd}" [(set_attr "type" "str") @@ -18116,7 +15506,7 @@ (set (match_operand:SI 1 "register_operand" "=S") (plus:SI (match_dup 3) (const_int 2))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "movsw" [(set_attr "type" "str") @@ -18132,7 +15522,7 @@ (set (match_operand:DI 1 "register_operand" "=S") (plus:DI (match_dup 3) (const_int 2))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "movsw" [(set_attr "type" "str") @@ -18148,7 +15538,7 @@ (set (match_operand:SI 1 "register_operand" "=S") (plus:SI (match_dup 3) (const_int 1))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "movsb" [(set_attr "type" "str") @@ -18164,7 +15554,7 @@ (set (match_operand:DI 1 "register_operand" "=S") (plus:DI (match_dup 3) (const_int 1))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "movsb" [(set_attr "type" "str") @@ -18180,7 +15570,7 @@ (set (match_operand 1 "memory_operand" "") (match_operand 3 "memory_operand" "")) (use (match_dup 4)) - (use (reg:SI DIRFLAG_REG))])] + (use (reg:SI 19))])] "" "") @@ -18196,7 +15586,7 @@ (set (mem:BLK (match_dup 3)) (mem:BLK (match_dup 4))) (use (match_dup 5)) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT" "{rep\;movsq|rep movsq}" [(set_attr "type" "str") @@ -18216,7 +15606,7 @@ (set (mem:BLK (match_dup 3)) (mem:BLK (match_dup 4))) (use (match_dup 5)) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "!TARGET_64BIT" "{rep\;movsl|rep movsd}" [(set_attr "type" "str") @@ -18236,7 +15626,7 @@ (set (mem:BLK (match_dup 3)) (mem:BLK (match_dup 4))) (use (match_dup 5)) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT" "{rep\;movsl|rep movsd}" [(set_attr "type" "str") @@ -18254,7 +15644,7 @@ (set (mem:BLK (match_dup 3)) (mem:BLK (match_dup 4))) (use (match_dup 5)) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "!TARGET_64BIT" "{rep\;movsb|rep movsb}" [(set_attr "type" "str") @@ -18272,7 +15662,7 @@ (set (mem:BLK (match_dup 3)) (mem:BLK (match_dup 4))) (use (match_dup 5)) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT" "{rep\;movsb|rep movsb}" [(set_attr "type" "str") @@ -18280,35 +15670,25 @@ (set_attr "memory" "both") (set_attr "mode" "SI")]) -(define_expand "setmemsi" +(define_expand "clrstrsi" [(use (match_operand:BLK 0 "memory_operand" "")) (use (match_operand:SI 1 "nonmemory_operand" "")) - (use (match_operand 2 "const_int_operand" "")) - (use (match_operand 3 "const_int_operand" ""))] + (use (match_operand 2 "const_int_operand" ""))] "" { - /* If value to set is not zero, use the library routine. */ - if (operands[2] != const0_rtx) - FAIL; - - if (ix86_expand_clrmem (operands[0], operands[1], operands[3])) + if (ix86_expand_clrstr (operands[0], operands[1], operands[2])) DONE; else FAIL; }) -(define_expand "setmemdi" +(define_expand "clrstrdi" [(use (match_operand:BLK 0 "memory_operand" "")) (use (match_operand:DI 1 "nonmemory_operand" "")) - (use (match_operand 2 "const_int_operand" "")) - (use (match_operand 3 "const_int_operand" ""))] + (use (match_operand 2 "const_int_operand" ""))] "TARGET_64BIT" { - /* If value to set is not zero, use the library routine. */ - if (operands[2] != const0_rtx) - FAIL; - - if (ix86_expand_clrmem (operands[0], operands[1], operands[3])) + if (ix86_expand_clrstr (operands[0], operands[1], operands[2])) DONE; else FAIL; @@ -18322,7 +15702,7 @@ (match_operand 2 "register_operand" "")) (parallel [(set (match_operand 0 "register_operand" "") (match_dup 3)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" { if (GET_MODE (operands[1]) != GET_MODE (operands[2])) @@ -18346,17 +15726,17 @@ (match_operand 2 "register_operand" "")) (set (match_operand 0 "register_operand" "") (match_operand 3 "" "")) - (use (reg:SI DIRFLAG_REG))])] + (use (reg:SI 19))])] "TARGET_SINGLE_STRINGOP || optimize_size" "") (define_insn "*strsetdi_rex_1" - [(set (mem:DI (match_operand:DI 1 "register_operand" "0")) - (match_operand:DI 2 "register_operand" "a")) + [(set (mem:SI (match_operand:DI 1 "register_operand" "0")) + (match_operand:SI 2 "register_operand" "a")) (set (match_operand:DI 0 "register_operand" "=D") (plus:DI (match_dup 1) (const_int 8))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "stosq" [(set_attr "type" "str") @@ -18369,7 +15749,7 @@ (set (match_operand:SI 0 "register_operand" "=D") (plus:SI (match_dup 1) (const_int 4))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "{stosl|stosd}" [(set_attr "type" "str") @@ -18382,7 +15762,7 @@ (set (match_operand:DI 0 "register_operand" "=D") (plus:DI (match_dup 1) (const_int 4))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "{stosl|stosd}" [(set_attr "type" "str") @@ -18395,7 +15775,7 @@ (set (match_operand:SI 0 "register_operand" "=D") (plus:SI (match_dup 1) (const_int 2))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "stosw" [(set_attr "type" "str") @@ -18408,7 +15788,7 @@ (set (match_operand:DI 0 "register_operand" "=D") (plus:DI (match_dup 1) (const_int 2))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "stosw" [(set_attr "type" "str") @@ -18421,7 +15801,7 @@ (set (match_operand:SI 0 "register_operand" "=D") (plus:SI (match_dup 1) (const_int 1))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "stosb" [(set_attr "type" "str") @@ -18434,7 +15814,7 @@ (set (match_operand:DI 0 "register_operand" "=D") (plus:DI (match_dup 1) (const_int 1))) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" "stosb" [(set_attr "type" "str") @@ -18448,7 +15828,7 @@ (set (match_operand 2 "memory_operand" "") (const_int 0)) (use (match_operand 3 "register_operand" "")) (use (match_dup 1)) - (use (reg:SI DIRFLAG_REG))])] + (use (reg:SI 19))])] "" "") @@ -18462,7 +15842,7 @@ (const_int 0)) (use (match_operand:DI 2 "register_operand" "a")) (use (match_dup 4)) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT" "{rep\;stosq|rep stosq}" [(set_attr "type" "str") @@ -18480,7 +15860,7 @@ (const_int 0)) (use (match_operand:SI 2 "register_operand" "a")) (use (match_dup 4)) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "!TARGET_64BIT" "{rep\;stosl|rep stosd}" [(set_attr "type" "str") @@ -18498,7 +15878,7 @@ (const_int 0)) (use (match_operand:SI 2 "register_operand" "a")) (use (match_dup 4)) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT" "{rep\;stosl|rep stosd}" [(set_attr "type" "str") @@ -18515,7 +15895,7 @@ (const_int 0)) (use (match_operand:QI 2 "register_operand" "a")) (use (match_dup 4)) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "!TARGET_64BIT" "{rep\;stosb|rep stosb}" [(set_attr "type" "str") @@ -18532,7 +15912,7 @@ (const_int 0)) (use (match_operand:QI 2 "register_operand" "a")) (use (match_dup 4)) - (use (reg:SI DIRFLAG_REG))] + (use (reg:SI 19))] "TARGET_64BIT" "{rep\;stosb|rep stosb}" [(set_attr "type" "str") @@ -18540,7 +15920,7 @@ (set_attr "memory" "store") (set_attr "mode" "QI")]) -(define_expand "cmpstrnsi" +(define_expand "cmpstrsi" [(set (match_operand:SI 0 "register_operand" "") (compare:SI (match_operand:BLK 1 "general_operand" "") (match_operand:BLK 2 "general_operand" ""))) @@ -18581,8 +15961,8 @@ emit_move_insn (operands[0], const0_rtx); DONE; } - emit_insn (gen_cmpstrnqi_nz_1 (addr1, addr2, countreg, align, - operands[1], operands[2])); + emit_insn (gen_cmpstrqi_nz_1 (addr1, addr2, countreg, align, + operands[1], operands[2])); } else { @@ -18590,8 +15970,8 @@ emit_insn (gen_cmpdi_1_rex64 (countreg, countreg)); else emit_insn (gen_cmpsi_1 (countreg, countreg)); - emit_insn (gen_cmpstrnqi_1 (addr1, addr2, countreg, align, - operands[1], operands[2])); + emit_insn (gen_cmpstrqi_1 (addr1, addr2, countreg, align, + operands[1], operands[2])); } outlow = gen_lowpart (QImode, out); @@ -18608,13 +15988,13 @@ (define_expand "cmpintqi" [(set (match_dup 1) - (gtu:QI (reg:CC FLAGS_REG) (const_int 0))) + (gtu:QI (reg:CC 17) (const_int 0))) (set (match_dup 2) - (ltu:QI (reg:CC FLAGS_REG) (const_int 0))) + (ltu:QI (reg:CC 17) (const_int 0))) (parallel [(set (match_operand:QI 0 "register_operand" "") (minus:QI (match_dup 1) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "operands[1] = gen_reg_rtx (QImode); operands[2] = gen_reg_rtx (QImode);") @@ -18622,26 +16002,26 @@ ;; memcmp recognizers. The `cmpsb' opcode does nothing if the count is ;; zero. Emit extra code to make sure that a zero-length compare is EQ. -(define_expand "cmpstrnqi_nz_1" - [(parallel [(set (reg:CC FLAGS_REG) +(define_expand "cmpstrqi_nz_1" + [(parallel [(set (reg:CC 17) (compare:CC (match_operand 4 "memory_operand" "") (match_operand 5 "memory_operand" ""))) (use (match_operand 2 "register_operand" "")) (use (match_operand:SI 3 "immediate_operand" "")) - (use (reg:SI DIRFLAG_REG)) + (use (reg:SI 19)) (clobber (match_operand 0 "register_operand" "")) (clobber (match_operand 1 "register_operand" "")) (clobber (match_dup 2))])] "" "") -(define_insn "*cmpstrnqi_nz_1" - [(set (reg:CC FLAGS_REG) +(define_insn "*cmpstrqi_nz_1" + [(set (reg:CC 17) (compare:CC (mem:BLK (match_operand:SI 4 "register_operand" "0")) (mem:BLK (match_operand:SI 5 "register_operand" "1")))) (use (match_operand:SI 6 "register_operand" "2")) (use (match_operand:SI 3 "immediate_operand" "i")) - (use (reg:SI DIRFLAG_REG)) + (use (reg:SI 19)) (clobber (match_operand:SI 0 "register_operand" "=S")) (clobber (match_operand:SI 1 "register_operand" "=D")) (clobber (match_operand:SI 2 "register_operand" "=c"))] @@ -18651,13 +16031,13 @@ (set_attr "mode" "QI") (set_attr "prefix_rep" "1")]) -(define_insn "*cmpstrnqi_nz_rex_1" - [(set (reg:CC FLAGS_REG) +(define_insn "*cmpstrqi_nz_rex_1" + [(set (reg:CC 17) (compare:CC (mem:BLK (match_operand:DI 4 "register_operand" "0")) (mem:BLK (match_operand:DI 5 "register_operand" "1")))) (use (match_operand:DI 6 "register_operand" "2")) (use (match_operand:SI 3 "immediate_operand" "i")) - (use (reg:SI DIRFLAG_REG)) + (use (reg:SI 19)) (clobber (match_operand:DI 0 "register_operand" "=S")) (clobber (match_operand:DI 1 "register_operand" "=D")) (clobber (match_operand:DI 2 "register_operand" "=c"))] @@ -18669,32 +16049,32 @@ ;; The same, but the count is not known to not be zero. -(define_expand "cmpstrnqi_1" - [(parallel [(set (reg:CC FLAGS_REG) +(define_expand "cmpstrqi_1" + [(parallel [(set (reg:CC 17) (if_then_else:CC (ne (match_operand 2 "register_operand" "") (const_int 0)) (compare:CC (match_operand 4 "memory_operand" "") (match_operand 5 "memory_operand" "")) (const_int 0))) (use (match_operand:SI 3 "immediate_operand" "")) - (use (reg:CC FLAGS_REG)) - (use (reg:SI DIRFLAG_REG)) + (use (reg:CC 17)) + (use (reg:SI 19)) (clobber (match_operand 0 "register_operand" "")) (clobber (match_operand 1 "register_operand" "")) (clobber (match_dup 2))])] "" "") -(define_insn "*cmpstrnqi_1" - [(set (reg:CC FLAGS_REG) +(define_insn "*cmpstrqi_1" + [(set (reg:CC 17) (if_then_else:CC (ne (match_operand:SI 6 "register_operand" "2") (const_int 0)) (compare:CC (mem:BLK (match_operand:SI 4 "register_operand" "0")) (mem:BLK (match_operand:SI 5 "register_operand" "1"))) (const_int 0))) (use (match_operand:SI 3 "immediate_operand" "i")) - (use (reg:CC FLAGS_REG)) - (use (reg:SI DIRFLAG_REG)) + (use (reg:CC 17)) + (use (reg:SI 19)) (clobber (match_operand:SI 0 "register_operand" "=S")) (clobber (match_operand:SI 1 "register_operand" "=D")) (clobber (match_operand:SI 2 "register_operand" "=c"))] @@ -18704,16 +16084,16 @@ (set_attr "mode" "QI") (set_attr "prefix_rep" "1")]) -(define_insn "*cmpstrnqi_rex_1" - [(set (reg:CC FLAGS_REG) +(define_insn "*cmpstrqi_rex_1" + [(set (reg:CC 17) (if_then_else:CC (ne (match_operand:DI 6 "register_operand" "2") (const_int 0)) (compare:CC (mem:BLK (match_operand:DI 4 "register_operand" "0")) (mem:BLK (match_operand:DI 5 "register_operand" "1"))) (const_int 0))) (use (match_operand:SI 3 "immediate_operand" "i")) - (use (reg:CC FLAGS_REG)) - (use (reg:SI DIRFLAG_REG)) + (use (reg:CC 17)) + (use (reg:SI 19)) (clobber (match_operand:DI 0 "register_operand" "=S")) (clobber (match_operand:DI 1 "register_operand" "=D")) (clobber (match_operand:DI 2 "register_operand" "=c"))] @@ -18751,9 +16131,9 @@ (define_expand "strlenqi_1" [(parallel [(set (match_operand 0 "register_operand" "") (match_operand 2 "" "")) - (use (reg:SI DIRFLAG_REG)) + (use (reg:SI 19)) (clobber (match_operand 1 "register_operand" "")) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") @@ -18763,9 +16143,9 @@ (match_operand:QI 2 "register_operand" "a") (match_operand:SI 3 "immediate_operand" "i") (match_operand:SI 4 "register_operand" "0")] UNSPEC_SCAS)) - (use (reg:SI DIRFLAG_REG)) + (use (reg:SI 19)) (clobber (match_operand:SI 1 "register_operand" "=D")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT" "repnz{\;| }scasb" [(set_attr "type" "str") @@ -18778,18 +16158,18 @@ (match_operand:QI 2 "register_operand" "a") (match_operand:DI 3 "immediate_operand" "i") (match_operand:DI 4 "register_operand" "0")] UNSPEC_SCAS)) - (use (reg:SI DIRFLAG_REG)) + (use (reg:SI 19)) (clobber (match_operand:DI 1 "register_operand" "=D")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "repnz{\;| }scasb" [(set_attr "type" "str") (set_attr "mode" "QI") (set_attr "prefix_rep" "1")]) -;; Peephole optimizations to clean up after cmpstrn*. This should be +;; Peephole optimizations to clean up after cmpstr*. This should be ;; handled in combine, but it is not currently up to the task. -;; When used for their truth value, the cmpstrn* expanders generate +;; When used for their truth value, the cmpstr* expanders generate ;; code like this: ;; ;; repz cmpsb @@ -18800,71 +16180,71 @@ ;; ;; The intermediate three instructions are unnecessary. -;; This one handles cmpstrn*_nz_1... +;; This one handles cmpstr*_nz_1... (define_peephole2 [(parallel[ - (set (reg:CC FLAGS_REG) + (set (reg:CC 17) (compare:CC (mem:BLK (match_operand 4 "register_operand" "")) (mem:BLK (match_operand 5 "register_operand" "")))) (use (match_operand 6 "register_operand" "")) (use (match_operand:SI 3 "immediate_operand" "")) - (use (reg:SI DIRFLAG_REG)) + (use (reg:SI 19)) (clobber (match_operand 0 "register_operand" "")) (clobber (match_operand 1 "register_operand" "")) (clobber (match_operand 2 "register_operand" ""))]) (set (match_operand:QI 7 "register_operand" "") - (gtu:QI (reg:CC FLAGS_REG) (const_int 0))) + (gtu:QI (reg:CC 17) (const_int 0))) (set (match_operand:QI 8 "register_operand" "") - (ltu:QI (reg:CC FLAGS_REG) (const_int 0))) - (set (reg FLAGS_REG) + (ltu:QI (reg:CC 17) (const_int 0))) + (set (reg 17) (compare (match_dup 7) (match_dup 8))) ] "peep2_reg_dead_p (4, operands[7]) && peep2_reg_dead_p (4, operands[8])" [(parallel[ - (set (reg:CC FLAGS_REG) + (set (reg:CC 17) (compare:CC (mem:BLK (match_dup 4)) (mem:BLK (match_dup 5)))) (use (match_dup 6)) (use (match_dup 3)) - (use (reg:SI DIRFLAG_REG)) + (use (reg:SI 19)) (clobber (match_dup 0)) (clobber (match_dup 1)) (clobber (match_dup 2))])] "") -;; ...and this one handles cmpstrn*_1. +;; ...and this one handles cmpstr*_1. (define_peephole2 [(parallel[ - (set (reg:CC FLAGS_REG) + (set (reg:CC 17) (if_then_else:CC (ne (match_operand 6 "register_operand" "") (const_int 0)) (compare:CC (mem:BLK (match_operand 4 "register_operand" "")) (mem:BLK (match_operand 5 "register_operand" ""))) (const_int 0))) (use (match_operand:SI 3 "immediate_operand" "")) - (use (reg:CC FLAGS_REG)) - (use (reg:SI DIRFLAG_REG)) + (use (reg:CC 17)) + (use (reg:SI 19)) (clobber (match_operand 0 "register_operand" "")) (clobber (match_operand 1 "register_operand" "")) (clobber (match_operand 2 "register_operand" ""))]) (set (match_operand:QI 7 "register_operand" "") - (gtu:QI (reg:CC FLAGS_REG) (const_int 0))) + (gtu:QI (reg:CC 17) (const_int 0))) (set (match_operand:QI 8 "register_operand" "") - (ltu:QI (reg:CC FLAGS_REG) (const_int 0))) - (set (reg FLAGS_REG) + (ltu:QI (reg:CC 17) (const_int 0))) + (set (reg 17) (compare (match_dup 7) (match_dup 8))) ] "peep2_reg_dead_p (4, operands[7]) && peep2_reg_dead_p (4, operands[8])" [(parallel[ - (set (reg:CC FLAGS_REG) + (set (reg:CC 17) (if_then_else:CC (ne (match_dup 6) (const_int 0)) (compare:CC (mem:BLK (match_dup 4)) (mem:BLK (match_dup 5))) (const_int 0))) (use (match_dup 3)) - (use (reg:CC FLAGS_REG)) - (use (reg:SI DIRFLAG_REG)) + (use (reg:CC 17)) + (use (reg:SI 19)) (clobber (match_dup 0)) (clobber (match_dup 1)) (clobber (match_dup 2))])] @@ -18887,7 +16267,7 @@ (if_then_else:DI (match_operand 1 "ix86_carry_flag_operator" "") (const_int -1) (const_int 0))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT" "sbb{q}\t%0, %0" ; Since we don't have the proper number of operands for an alu insn, @@ -18899,10 +16279,10 @@ (set_attr "mode" "DI") (set_attr "length_immediate" "0")]) -(define_insn "*movdicc_c_rex64" +(define_insn "movdicc_c_rex64" [(set (match_operand:DI 0 "register_operand" "=r,r") (if_then_else:DI (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (match_operand:DI 2 "nonimmediate_operand" "rm,0") (match_operand:DI 3 "nonimmediate_operand" "0,rm")))] "TARGET_64BIT && TARGET_CMOVE @@ -18930,7 +16310,7 @@ (if_then_else:SI (match_operand 1 "ix86_carry_flag_operator" "") (const_int -1) (const_int 0))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "" "sbb{l}\t%0, %0" ; Since we don't have the proper number of operands for an alu insn, @@ -18945,7 +16325,7 @@ (define_insn "*movsicc_noc" [(set (match_operand:SI 0 "register_operand" "=r,r") (if_then_else:SI (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (match_operand:SI 2 "nonimmediate_operand" "rm,0") (match_operand:SI 3 "nonimmediate_operand" "0,rm")))] "TARGET_CMOVE @@ -18967,7 +16347,7 @@ (define_insn "*movhicc_noc" [(set (match_operand:HI 0 "register_operand" "=r,r") (if_then_else:HI (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (match_operand:HI 2 "nonimmediate_operand" "rm,0") (match_operand:HI 3 "nonimmediate_operand" "0,rm")))] "TARGET_CMOVE @@ -18989,8 +16369,7 @@ (define_insn_and_split "*movqicc_noc" [(set (match_operand:QI 0 "register_operand" "=r,r") (if_then_else:QI (match_operator 1 "ix86_comparison_operator" - [(match_operand 4 "flags_reg_operand" "") - (const_int 0)]) + [(match_operand 4 "flags_reg_operand" "") (const_int 0)]) (match_operand:QI 2 "register_operand" "r,0") (match_operand:QI 3 "register_operand" "0,r")))] "TARGET_CMOVE && !TARGET_PARTIAL_REG_STALL" @@ -19011,16 +16390,16 @@ (if_then_else:SF (match_operand 1 "comparison_operator" "") (match_operand:SF 2 "register_operand" "") (match_operand:SF 3 "register_operand" "")))] - "(TARGET_80387 && TARGET_CMOVE) || TARGET_SSE_MATH" + "TARGET_CMOVE" "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;") -(define_insn "*movsfcc_1_387" - [(set (match_operand:SF 0 "register_operand" "=f,f,r,r") +(define_insn "*movsfcc_1" + [(set (match_operand:SF 0 "register_operand" "=f#r,f#r,r#f,r#f") (if_then_else:SF (match_operator 1 "fcmov_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) - (match_operand:SF 2 "nonimmediate_operand" "f,0,rm,0") - (match_operand:SF 3 "nonimmediate_operand" "0,f,0,rm")))] - "TARGET_80387 && TARGET_CMOVE + [(reg 17) (const_int 0)]) + (match_operand:SF 2 "nonimmediate_operand" "f#r,0,rm#f,0") + (match_operand:SF 3 "nonimmediate_operand" "0,f#r,0,rm#f")))] + "TARGET_CMOVE && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" "@ fcmov%F1\t{%2, %0|%0, %2} @@ -19035,16 +16414,16 @@ (if_then_else:DF (match_operand 1 "comparison_operator" "") (match_operand:DF 2 "register_operand" "") (match_operand:DF 3 "register_operand" "")))] - "(TARGET_80387 && TARGET_CMOVE) || (TARGET_SSE2 && TARGET_SSE_MATH)" + "TARGET_CMOVE" "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;") (define_insn "*movdfcc_1" - [(set (match_operand:DF 0 "register_operand" "=f,f,&r,&r") + [(set (match_operand:DF 0 "register_operand" "=f#r,f#r,&r#f,&r#f") (if_then_else:DF (match_operator 1 "fcmov_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) - (match_operand:DF 2 "nonimmediate_operand" "f,0,rm,0") - (match_operand:DF 3 "nonimmediate_operand" "0,f,0,rm")))] - "!TARGET_64BIT && TARGET_80387 && TARGET_CMOVE + [(reg 17) (const_int 0)]) + (match_operand:DF 2 "nonimmediate_operand" "f#r,0,rm#f,0") + (match_operand:DF 3 "nonimmediate_operand" "0,f#r,0,rm#f")))] + "!TARGET_64BIT && TARGET_CMOVE && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" "@ fcmov%F1\t{%2, %0|%0, %2} @@ -19055,12 +16434,12 @@ (set_attr "mode" "DF")]) (define_insn "*movdfcc_1_rex64" - [(set (match_operand:DF 0 "register_operand" "=f,f,r,r") + [(set (match_operand:DF 0 "register_operand" "=f#r,f#r,r#f,r#f") (if_then_else:DF (match_operator 1 "fcmov_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) - (match_operand:DF 2 "nonimmediate_operand" "f,0,rm,0") - (match_operand:DF 3 "nonimmediate_operand" "0,f,0,rm")))] - "TARGET_64BIT && TARGET_80387 && TARGET_CMOVE + [(reg 17) (const_int 0)]) + (match_operand:DF 2 "nonimmediate_operand" "f#r,0#r,rm#f,0#f") + (match_operand:DF 3 "nonimmediate_operand" "0#r,f#r,0#f,rm#f")))] + "TARGET_64BIT && TARGET_CMOVE && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" "@ fcmov%F1\t{%2, %0|%0, %2} @@ -19073,8 +16452,7 @@ (define_split [(set (match_operand:DF 0 "register_and_not_any_fp_reg_operand" "") (if_then_else:DF (match_operator 1 "fcmov_comparison_operator" - [(match_operand 4 "flags_reg_operand" "") - (const_int 0)]) + [(match_operand 4 "flags_reg_operand" "") (const_int 0)]) (match_operand:DF 2 "nonimmediate_operand" "") (match_operand:DF 3 "nonimmediate_operand" "")))] "!TARGET_64BIT && reload_completed" @@ -19095,134 +16473,71 @@ (if_then_else:XF (match_operand 1 "comparison_operator" "") (match_operand:XF 2 "register_operand" "") (match_operand:XF 3 "register_operand" "")))] - "TARGET_80387 && TARGET_CMOVE" + "TARGET_CMOVE" "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;") (define_insn "*movxfcc_1" [(set (match_operand:XF 0 "register_operand" "=f,f") (if_then_else:XF (match_operator 1 "fcmov_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (match_operand:XF 2 "register_operand" "f,0") (match_operand:XF 3 "register_operand" "0,f")))] - "TARGET_80387 && TARGET_CMOVE" + "TARGET_CMOVE" "@ fcmov%F1\t{%2, %0|%0, %2} fcmov%f1\t{%3, %0|%0, %3}" [(set_attr "type" "fcmov") (set_attr "mode" "XF")]) -;; These versions of the min/max patterns are intentionally ignorant of -;; their behavior wrt -0.0 and NaN (via the commutative operand mark). -;; Since both the tree-level MAX_EXPR and the rtl-level SMAX operator -;; are undefined in this condition, we're certain this is correct. - -(define_insn "sminsf3" - [(set (match_operand:SF 0 "register_operand" "=x") - (smin:SF (match_operand:SF 1 "nonimmediate_operand" "%0") - (match_operand:SF 2 "nonimmediate_operand" "xm")))] - "TARGET_SSE_MATH" - "minss\t{%2, %0|%0, %2}" - [(set_attr "type" "sseadd") - (set_attr "mode" "SF")]) - -(define_insn "smaxsf3" - [(set (match_operand:SF 0 "register_operand" "=x") - (smax:SF (match_operand:SF 1 "nonimmediate_operand" "%0") - (match_operand:SF 2 "nonimmediate_operand" "xm")))] - "TARGET_SSE_MATH" - "maxss\t{%2, %0|%0, %2}" - [(set_attr "type" "sseadd") - (set_attr "mode" "SF")]) - -(define_insn "smindf3" - [(set (match_operand:DF 0 "register_operand" "=x") - (smin:DF (match_operand:DF 1 "nonimmediate_operand" "%0") - (match_operand:DF 2 "nonimmediate_operand" "xm")))] - "TARGET_SSE2 && TARGET_SSE_MATH" - "minsd\t{%2, %0|%0, %2}" - [(set_attr "type" "sseadd") - (set_attr "mode" "DF")]) - -(define_insn "smaxdf3" - [(set (match_operand:DF 0 "register_operand" "=x") - (smax:DF (match_operand:DF 1 "nonimmediate_operand" "%0") - (match_operand:DF 2 "nonimmediate_operand" "xm")))] - "TARGET_SSE2 && TARGET_SSE_MATH" - "maxsd\t{%2, %0|%0, %2}" - [(set_attr "type" "sseadd") - (set_attr "mode" "DF")]) - -;; These versions of the min/max patterns implement exactly the operations -;; min = (op1 < op2 ? op1 : op2) -;; max = (!(op1 < op2) ? op1 : op2) -;; Their operands are not commutative, and thus they may be used in the -;; presence of -0.0 and NaN. - -(define_insn "*ieee_sminsf3" - [(set (match_operand:SF 0 "register_operand" "=x") - (unspec:SF [(match_operand:SF 1 "register_operand" "0") - (match_operand:SF 2 "nonimmediate_operand" "xm")] - UNSPEC_IEEE_MIN))] - "TARGET_SSE_MATH" - "minss\t{%2, %0|%0, %2}" - [(set_attr "type" "sseadd") - (set_attr "mode" "SF")]) - -(define_insn "*ieee_smaxsf3" - [(set (match_operand:SF 0 "register_operand" "=x") - (unspec:SF [(match_operand:SF 1 "register_operand" "0") - (match_operand:SF 2 "nonimmediate_operand" "xm")] - UNSPEC_IEEE_MAX))] - "TARGET_SSE_MATH" - "maxss\t{%2, %0|%0, %2}" - [(set_attr "type" "sseadd") - (set_attr "mode" "SF")]) - -(define_insn "*ieee_smindf3" - [(set (match_operand:DF 0 "register_operand" "=x") - (unspec:DF [(match_operand:DF 1 "register_operand" "0") - (match_operand:DF 2 "nonimmediate_operand" "xm")] - UNSPEC_IEEE_MIN))] - "TARGET_SSE2 && TARGET_SSE_MATH" - "minsd\t{%2, %0|%0, %2}" - [(set_attr "type" "sseadd") - (set_attr "mode" "DF")]) +(define_expand "minsf3" + [(parallel [ + (set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))])] + "TARGET_SSE" + "") -(define_insn "*ieee_smaxdf3" - [(set (match_operand:DF 0 "register_operand" "=x") - (unspec:DF [(match_operand:DF 1 "register_operand" "0") - (match_operand:DF 2 "nonimmediate_operand" "xm")] - UNSPEC_IEEE_MAX))] - "TARGET_SSE2 && TARGET_SSE_MATH" - "maxsd\t{%2, %0|%0, %2}" - [(set_attr "type" "sseadd") - (set_attr "mode" "DF")]) +(define_insn "*minsf" + [(set (match_operand:SF 0 "register_operand" "=x#f,f#x,f#x") + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "0,0,f#x") + (match_operand:SF 2 "nonimmediate_operand" "xm#f,f#x,0")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE && TARGET_IEEE_FP" + "#") -;; Make two stack loads independent: -;; fld aa fld aa -;; fld %st(0) -> fld bb -;; fmul bb fmul %st(1), %st -;; -;; Actually we only match the last two instructions for simplicity. -(define_peephole2 - [(set (match_operand 0 "fp_register_operand" "") - (match_operand 1 "fp_register_operand" "")) - (set (match_dup 0) - (match_operator 2 "binary_fp_operator" - [(match_dup 0) - (match_operand 3 "memory_operand" "")]))] - "REGNO (operands[0]) != REGNO (operands[1])" - [(set (match_dup 0) (match_dup 3)) - (set (match_dup 0) (match_dup 4))] +(define_insn "*minsf_nonieee" + [(set (match_operand:SF 0 "register_operand" "=x#f,f#x") + (if_then_else:SF (lt (match_operand:SF 1 "nonimmediate_operand" "%0,0") + (match_operand:SF 2 "nonimmediate_operand" "xm#f,f#x")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE && !TARGET_IEEE_FP + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "#") - ;; The % modifier is not operational anymore in peephole2's, so we have to - ;; swap the operands manually in the case of addition and multiplication. - "if (COMMUTATIVE_ARITH_P (operands[2])) - operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[2]), GET_MODE (operands[2]), - operands[0], operands[1]); - else - operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[2]), GET_MODE (operands[2]), - operands[1], operands[0]);") +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")) + (match_operand:SF 3 "register_operand" "") + (match_operand:SF 4 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (match_dup 0) + (if_then_else:SF (lt (match_dup 1) + (match_dup 2)) + (match_dup 1) + (match_dup 2)))]) ;; Conditional addition patterns (define_expand "addqicc" @@ -19257,6 +16572,282 @@ "TARGET_64BIT" "if (!ix86_expand_int_addcc (operands)) FAIL; DONE;") +;; We can't represent the LT test directly. Do this by swapping the operands. + +(define_split + [(set (match_operand:SF 0 "fp_register_operand" "") + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "register_operand" "")) + (match_operand:SF 3 "register_operand" "") + (match_operand:SF 4 "register_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (reg:CCFP 17) + (compare:CCFP (match_dup 2) + (match_dup 1))) + (set (match_dup 0) + (if_then_else:SF (ge (reg:CCFP 17) (const_int 0)) + (match_dup 1) + (match_dup 2)))]) + +(define_insn "*minsf_sse" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (match_dup 2)))] + "TARGET_SSE && reload_completed" + "minss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +(define_expand "mindf3" + [(parallel [ + (set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))])] + "TARGET_SSE2 && TARGET_SSE_MATH" + "#") + +(define_insn "*mindf" + [(set (match_operand:DF 0 "register_operand" "=Y#f,f#Y,f#Y") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "0,0,f#Y") + (match_operand:DF 2 "nonimmediate_operand" "Ym#f,f#Y,0")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE2 && TARGET_IEEE_FP && TARGET_SSE_MATH" + "#") + +(define_insn "*mindf_nonieee" + [(set (match_operand:DF 0 "register_operand" "=Y#f,f#Y") + (if_then_else:DF (lt (match_operand:DF 1 "nonimmediate_operand" "%0,0") + (match_operand:DF 2 "nonimmediate_operand" "Ym#f,f#Y")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE2 && TARGET_SSE_MATH && !TARGET_IEEE_FP + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "#") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")) + (match_operand:DF 3 "register_operand" "") + (match_operand:DF 4 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (match_dup 0) + (if_then_else:DF (lt (match_dup 1) + (match_dup 2)) + (match_dup 1) + (match_dup 2)))]) + +;; We can't represent the LT test directly. Do this by swapping the operands. +(define_split + [(set (match_operand:DF 0 "fp_register_operand" "") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "register_operand" "")) + (match_operand:DF 3 "register_operand" "") + (match_operand:DF 4 "register_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (reg:CCFP 17) + (compare:CCFP (match_dup 2) + (match_dup 1))) + (set (match_dup 0) + (if_then_else:DF (ge (reg:CCFP 17) (const_int 0)) + (match_dup 1) + (match_dup 2)))]) + +(define_insn "*mindf_sse" + [(set (match_operand:DF 0 "register_operand" "=Y") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "nonimmediate_operand" "Ym")) + (match_dup 1) + (match_dup 2)))] + "TARGET_SSE2 && TARGET_SSE_MATH && reload_completed" + "minsd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "DF")]) + +(define_expand "maxsf3" + [(parallel [ + (set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))])] + "TARGET_SSE" + "#") + +(define_insn "*maxsf" + [(set (match_operand:SF 0 "register_operand" "=x#f,f#x,f#x") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "0,0,f#x") + (match_operand:SF 2 "nonimmediate_operand" "xm#f,f#x,0")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE && TARGET_IEEE_FP" + "#") + +(define_insn "*maxsf_nonieee" + [(set (match_operand:SF 0 "register_operand" "=x#f,f#x") + (if_then_else:SF (gt (match_operand:SF 1 "nonimmediate_operand" "%0,0") + (match_operand:SF 2 "nonimmediate_operand" "xm#f,f#x")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE && !TARGET_IEEE_FP + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "#") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")) + (match_operand:SF 3 "register_operand" "") + (match_operand:SF 4 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (match_dup 0) + (if_then_else:SF (gt (match_dup 1) + (match_dup 2)) + (match_dup 1) + (match_dup 2)))]) + +(define_split + [(set (match_operand:SF 0 "fp_register_operand" "") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "register_operand" "")) + (match_operand:SF 3 "register_operand" "") + (match_operand:SF 4 "register_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (reg:CCFP 17) + (compare:CCFP (match_dup 1) + (match_dup 2))) + (set (match_dup 0) + (if_then_else:SF (gt (reg:CCFP 17) (const_int 0)) + (match_dup 1) + (match_dup 2)))]) + +(define_insn "*maxsf_sse" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (match_dup 2)))] + "TARGET_SSE && reload_completed" + "maxss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +(define_expand "maxdf3" + [(parallel [ + (set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))])] + "TARGET_SSE2 && TARGET_SSE_MATH" + "#") + +(define_insn "*maxdf" + [(set (match_operand:DF 0 "register_operand" "=Y#f,f#Y,f#Y") + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "0,0,f#Y") + (match_operand:DF 2 "nonimmediate_operand" "Ym#f,f#Y,0")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE2 && TARGET_SSE_MATH && TARGET_IEEE_FP" + "#") + +(define_insn "*maxdf_nonieee" + [(set (match_operand:DF 0 "register_operand" "=Y#f,f#Y") + (if_then_else:DF (gt (match_operand:DF 1 "nonimmediate_operand" "%0,0") + (match_operand:DF 2 "nonimmediate_operand" "Ym#f,f#Y")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE2 && TARGET_SSE_MATH && !TARGET_IEEE_FP + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "#") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")) + (match_operand:DF 3 "register_operand" "") + (match_operand:DF 4 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (match_dup 0) + (if_then_else:DF (gt (match_dup 1) + (match_dup 2)) + (match_dup 1) + (match_dup 2)))]) + +(define_split + [(set (match_operand:DF 0 "fp_register_operand" "") + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "register_operand" "")) + (match_operand:DF 3 "register_operand" "") + (match_operand:DF 4 "register_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (reg:CCFP 17) + (compare:CCFP (match_dup 1) + (match_dup 2))) + (set (match_dup 0) + (if_then_else:DF (gt (reg:CCFP 17) (const_int 0)) + (match_dup 1) + (match_dup 2)))]) + +(define_insn "*maxdf_sse" + [(set (match_operand:DF 0 "register_operand" "=Y") + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "nonimmediate_operand" "Ym")) + (match_dup 1) + (match_dup 2)))] + "TARGET_SSE2 && TARGET_SSE_MATH && reload_completed" + "maxsd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "DF")]) ;; Misc patterns (?) @@ -19273,7 +16864,7 @@ [(set (match_operand:SI 0 "register_operand" "=r,r") (plus:SI (match_operand:SI 1 "register_operand" "0,r") (match_operand:SI 2 "immediate_operand" "i,i"))) - (clobber (reg:CC FLAGS_REG)) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))] "!TARGET_64BIT" { @@ -19298,7 +16889,7 @@ return "lea{l}\t{%a2, %0|%0, %a2}"; default: - gcc_unreachable (); + abort (); } } [(set (attr "type") @@ -19314,7 +16905,7 @@ [(set (match_operand:DI 0 "register_operand" "=r,r") (plus:DI (match_operand:DI 1 "register_operand" "0,r") (match_operand:DI 2 "x86_64_immediate_operand" "e,e"))) - (clobber (reg:CC FLAGS_REG)) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))] "TARGET_64BIT" { @@ -19341,7 +16932,7 @@ return "lea{q}\t{%a2, %0|%0, %a2}"; default: - gcc_unreachable (); + abort (); } } [(set (attr "type") @@ -19358,7 +16949,7 @@ (plus:DI (match_operand:DI 1 "register_operand" "0,r") (match_operand:DI 3 "immediate_operand" "i,i"))) (use (match_operand:DI 2 "register_operand" "r,r")) - (clobber (reg:CC FLAGS_REG)) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))] "TARGET_64BIT" { @@ -19372,12 +16963,372 @@ return "lea{q}\t{%a2, %0|%0, %a2}"; default: - gcc_unreachable (); + abort (); } } [(set_attr "type" "alu,lea") (set_attr "mode" "DI")]) +;; Placeholder for the conditional moves. This one is split either to SSE +;; based moves emulation or to usual cmove sequence. Little bit unfortunate +;; fact is that compares supported by the cmp??ss instructions are exactly +;; swapped of those supported by cmove sequence. +;; The EQ/NE comparisons also needs bit care, since they are not directly +;; supported by i387 comparisons and we do need to emit two conditional moves +;; in tandem. + +(define_insn "sse_movsfcc" + [(set (match_operand:SF 0 "register_operand" "=&x#rf,x#rf,?f#xr,?f#xr,?f#xr,?f#xr,?r#xf,?r#xf,?r#xf,?r#xf") + (if_then_else:SF (match_operator 1 "sse_comparison_operator" + [(match_operand:SF 4 "nonimmediate_operand" "0#fx,x#fx,f#x,f#x,xm#f,xm#f,f#x,f#x,xm#f,xm#f") + (match_operand:SF 5 "nonimmediate_operand" "xm#f,xm#f,f#x,f#x,x#f,x#f,f#x,f#x,x#f,x#f")]) + (match_operand:SF 2 "nonimmediate_operand" "x#fr,0#fr,f#fx,0#fx,f#fx,0#fx,rm#rx,0#rx,rm#rx,0#rx") + (match_operand:SF 3 "nonimmediate_operand" "x#fr,x#fr,0#fx,f#fx,0#fx,f#fx,0#fx,rm#rx,0#rx,rm#rx"))) + (clobber (match_scratch:SF 6 "=2,&4,X,X,X,X,X,X,X,X")) + (clobber (reg:CC 17))] + "TARGET_SSE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM) + /* Avoid combine from being smart and converting min/max + instruction patterns into conditional moves. */ + && ((GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != GT + && GET_CODE (operands[1]) != UNLE && GET_CODE (operands[1]) != UNGE) + || !rtx_equal_p (operands[4], operands[2]) + || !rtx_equal_p (operands[5], operands[3])) + && (!TARGET_IEEE_FP + || (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE))" + "#") + +(define_insn "sse_movsfcc_eq" + [(set (match_operand:SF 0 "register_operand" "=&x#rf,x#rf,?f#xr,?f#xr,?r#xf,?r#xf") + (if_then_else:SF (eq (match_operand:SF 3 "nonimmediate_operand" "%0#fx,x#fx,f#x,xm#f,f#x,xm#f") + (match_operand:SF 4 "nonimmediate_operand" "xm#f,xm#f,f#x,x#f,f#x,x#f")) + (match_operand:SF 1 "nonimmediate_operand" "x#fr,0#fr,0#fx,0#fx,0#rx,0#rx") + (match_operand:SF 2 "nonimmediate_operand" "x#fr,x#fr,f#fx,f#fx,rm#rx,rm#rx"))) + (clobber (match_scratch:SF 5 "=1,&3,X,X,X,X")) + (clobber (reg:CC 17))] + "TARGET_SSE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" + "#") + +(define_insn "sse_movdfcc" + [(set (match_operand:DF 0 "register_operand" "=&Y#rf,Y#rf,?f#Yr,?f#Yr,?f#Yr,?f#Yr,?r#Yf,?r#Yf,?r#Yf,?r#Yf") + (if_then_else:DF (match_operator 1 "sse_comparison_operator" + [(match_operand:DF 4 "nonimmediate_operand" "0#fY,Y#fY,f#Y,f#Y,Ym#f,Ym#f,f#Y,f#Y,Ym#f,Ym#f") + (match_operand:DF 5 "nonimmediate_operand" "Ym#f,Ym#f,f#Y,f#Y,Y#f,Y#f,f#Y,f#Y,Y#f,Y#f")]) + (match_operand:DF 2 "nonimmediate_operand" "Y#fr,0#fr,f#fY,0#fY,f#fY,0#fY,rm#rY,0#rY,rm#rY,0#rY") + (match_operand:DF 3 "nonimmediate_operand" "Y#fr,Y#fr,0#fY,f#fY,0#fY,f#fY,0#fY,rm#rY,0#rY,rm#rY"))) + (clobber (match_scratch:DF 6 "=2,&4,X,X,X,X,X,X,X,X")) + (clobber (reg:CC 17))] + "TARGET_SSE2 + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM) + /* Avoid combine from being smart and converting min/max + instruction patterns into conditional moves. */ + && ((GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != GT + && GET_CODE (operands[1]) != UNLE && GET_CODE (operands[1]) != UNGE) + || !rtx_equal_p (operands[4], operands[2]) + || !rtx_equal_p (operands[5], operands[3])) + && (!TARGET_IEEE_FP + || (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE))" + "#") + +(define_insn "sse_movdfcc_eq" + [(set (match_operand:DF 0 "register_operand" "=&Y#rf,Y#rf,?f#Yr,?f#Yr,?r#Yf,?r#Yf") + (if_then_else:DF (eq (match_operand:DF 3 "nonimmediate_operand" "%0#fY,Y#fY,f#Y,Ym#f,f#Y,Ym#f") + (match_operand:DF 4 "nonimmediate_operand" "Ym#f,Ym#f,f#Y,Y#f,f#Y,Y#f")) + (match_operand:DF 1 "nonimmediate_operand" "Y#fr,0#fr,0#fY,0#fY,0#rY,0#rY") + (match_operand:DF 2 "nonimmediate_operand" "Y#fr,Y#fr,f#fY,f#fY,rm#rY,rm#rY"))) + (clobber (match_scratch:DF 5 "=1,&3,X,X,X,X")) + (clobber (reg:CC 17))] + "TARGET_SSE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" + "#") + +;; For non-sse moves just expand the usual cmove sequence. +(define_split + [(set (match_operand 0 "register_operand" "") + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand 4 "nonimmediate_operand" "") + (match_operand 5 "register_operand" "")]) + (match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "nonimmediate_operand" ""))) + (clobber (match_operand 6 "" "")) + (clobber (reg:CC 17))] + "!SSE_REG_P (operands[0]) && reload_completed + && (GET_MODE (operands[0]) == SFmode + || (TARGET_SSE2 && GET_MODE (operands[0]) == DFmode))" + [(const_int 0)] +{ + ix86_compare_op0 = operands[5]; + ix86_compare_op1 = operands[4]; + operands[1] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[1])), + VOIDmode, operands[5], operands[4]); + ix86_expand_fp_movcc (operands); + DONE; +}) + +;; Split SSE based conditional move into sequence: +;; cmpCC op0, op4 - set op0 to 0 or ffffffff depending on the comparison +;; and op2, op0 - zero op2 if comparison was false +;; nand op0, op3 - load op3 to op0 if comparison was false +;; or op2, op0 - get the nonzero one into the result. +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (match_operator 1 "sse_comparison_operator" + [(match_operand:SF 4 "register_operand" "") + (match_operand:SF 5 "nonimmediate_operand" "")]) + (match_operand:SF 2 "register_operand" "") + (match_operand:SF 3 "register_operand" ""))) + (clobber (match_operand 6 "" "")) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed" + [(set (match_dup 4) (match_op_dup 1 [(match_dup 4) (match_dup 5)])) + (set (match_dup 2) (and:V4SF (match_dup 2) + (match_dup 8))) + (set (match_dup 8) (and:V4SF (not:V4SF (match_dup 8)) + (match_dup 3))) + (set (match_dup 0) (ior:V4SF (match_dup 6) + (match_dup 7)))] +{ + /* If op2 == op3, op3 would be clobbered before it is used. */ + if (operands_match_p (operands[2], operands[3])) + { + emit_move_insn (operands[0], operands[2]); + DONE; + } + + PUT_MODE (operands[1], GET_MODE (operands[0])); + if (operands_match_p (operands[0], operands[4])) + operands[6] = operands[4], operands[7] = operands[2]; + else + operands[6] = operands[2], operands[7] = operands[4]; + operands[0] = simplify_gen_subreg (V4SFmode, operands[0], SFmode, 0); + operands[2] = simplify_gen_subreg (V4SFmode, operands[2], SFmode, 0); + operands[3] = simplify_gen_subreg (V4SFmode, operands[3], SFmode, 0); + operands[8] = simplify_gen_subreg (V4SFmode, operands[4], SFmode, 0); + operands[6] = simplify_gen_subreg (V4SFmode, operands[6], SFmode, 0); + operands[7] = simplify_gen_subreg (V4SFmode, operands[7], SFmode, 0); +}) + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (match_operator 1 "sse_comparison_operator" + [(match_operand:DF 4 "register_operand" "") + (match_operand:DF 5 "nonimmediate_operand" "")]) + (match_operand:DF 2 "register_operand" "") + (match_operand:DF 3 "register_operand" ""))) + (clobber (match_operand 6 "" "")) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed" + [(set (match_dup 4) (match_op_dup 1 [(match_dup 4) (match_dup 5)])) + (set (match_dup 2) (and:V2DF (match_dup 2) + (match_dup 8))) + (set (match_dup 8) (and:V2DF (not:V2DF (match_dup 8)) + (match_dup 3))) + (set (match_dup 0) (ior:V2DF (match_dup 6) + (match_dup 7)))] +{ + if (GET_MODE (operands[2]) == DFmode + && TARGET_SSE_PARTIAL_REGS && !optimize_size) + { + rtx op = simplify_gen_subreg (V2DFmode, operands[2], DFmode, 0); + emit_insn (gen_sse2_unpcklpd (op, op, op)); + op = simplify_gen_subreg (V2DFmode, operands[3], DFmode, 0); + emit_insn (gen_sse2_unpcklpd (op, op, op)); + } + + /* If op2 == op3, op3 would be clobbered before it is used. */ + if (operands_match_p (operands[2], operands[3])) + { + emit_move_insn (operands[0], operands[2]); + DONE; + } + + PUT_MODE (operands[1], GET_MODE (operands[0])); + if (operands_match_p (operands[0], operands[4])) + operands[6] = operands[4], operands[7] = operands[2]; + else + operands[6] = operands[2], operands[7] = operands[4]; + operands[0] = simplify_gen_subreg (V2DFmode, operands[0], DFmode, 0); + operands[2] = simplify_gen_subreg (V2DFmode, operands[2], DFmode, 0); + operands[3] = simplify_gen_subreg (V2DFmode, operands[3], DFmode, 0); + operands[8] = simplify_gen_subreg (V2DFmode, operands[4], DFmode, 0); + operands[6] = simplify_gen_subreg (V2DFmode, operands[6], DFmode, 0); + operands[7] = simplify_gen_subreg (V2DFmode, operands[7], DFmode, 0); +}) + +;; Special case of conditional move we can handle effectively. +;; Do not brother with the integer/floating point case, since these are +;; bot considerably slower, unlike in the generic case. +(define_insn "*sse_movsfcc_const0_1" + [(set (match_operand:SF 0 "register_operand" "=&x") + (if_then_else:SF (match_operator 1 "sse_comparison_operator" + [(match_operand:SF 4 "register_operand" "0") + (match_operand:SF 5 "nonimmediate_operand" "xm")]) + (match_operand:SF 2 "register_operand" "x") + (match_operand:SF 3 "const0_operand" "X")))] + "TARGET_SSE" + "#") + +(define_insn "*sse_movsfcc_const0_2" + [(set (match_operand:SF 0 "register_operand" "=&x") + (if_then_else:SF (match_operator 1 "sse_comparison_operator" + [(match_operand:SF 4 "register_operand" "0") + (match_operand:SF 5 "nonimmediate_operand" "xm")]) + (match_operand:SF 2 "const0_operand" "X") + (match_operand:SF 3 "register_operand" "x")))] + "TARGET_SSE" + "#") + +(define_insn "*sse_movsfcc_const0_3" + [(set (match_operand:SF 0 "register_operand" "=&x") + (if_then_else:SF (match_operator 1 "fcmov_comparison_operator" + [(match_operand:SF 4 "nonimmediate_operand" "xm") + (match_operand:SF 5 "register_operand" "0")]) + (match_operand:SF 2 "register_operand" "x") + (match_operand:SF 3 "const0_operand" "X")))] + "TARGET_SSE" + "#") + +(define_insn "*sse_movsfcc_const0_4" + [(set (match_operand:SF 0 "register_operand" "=&x") + (if_then_else:SF (match_operator 1 "fcmov_comparison_operator" + [(match_operand:SF 4 "nonimmediate_operand" "xm") + (match_operand:SF 5 "register_operand" "0")]) + (match_operand:SF 2 "const0_operand" "X") + (match_operand:SF 3 "register_operand" "x")))] + "TARGET_SSE" + "#") + +(define_insn "*sse_movdfcc_const0_1" + [(set (match_operand:DF 0 "register_operand" "=&Y") + (if_then_else:DF (match_operator 1 "sse_comparison_operator" + [(match_operand:DF 4 "register_operand" "0") + (match_operand:DF 5 "nonimmediate_operand" "Ym")]) + (match_operand:DF 2 "register_operand" "Y") + (match_operand:DF 3 "const0_operand" "X")))] + "TARGET_SSE2" + "#") + +(define_insn "*sse_movdfcc_const0_2" + [(set (match_operand:DF 0 "register_operand" "=&Y") + (if_then_else:DF (match_operator 1 "sse_comparison_operator" + [(match_operand:DF 4 "register_operand" "0") + (match_operand:DF 5 "nonimmediate_operand" "Ym")]) + (match_operand:DF 2 "const0_operand" "X") + (match_operand:DF 3 "register_operand" "Y")))] + "TARGET_SSE2" + "#") + +(define_insn "*sse_movdfcc_const0_3" + [(set (match_operand:DF 0 "register_operand" "=&Y") + (if_then_else:DF (match_operator 1 "fcmov_comparison_operator" + [(match_operand:DF 4 "nonimmediate_operand" "Ym") + (match_operand:DF 5 "register_operand" "0")]) + (match_operand:DF 2 "register_operand" "Y") + (match_operand:DF 3 "const0_operand" "X")))] + "TARGET_SSE2" + "#") + +(define_insn "*sse_movdfcc_const0_4" + [(set (match_operand:DF 0 "register_operand" "=&Y") + (if_then_else:DF (match_operator 1 "fcmov_comparison_operator" + [(match_operand:DF 4 "nonimmediate_operand" "Ym") + (match_operand:DF 5 "register_operand" "0")]) + (match_operand:DF 2 "const0_operand" "X") + (match_operand:DF 3 "register_operand" "Y")))] + "TARGET_SSE2" + "#") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(match_operand:SF 4 "nonimmediate_operand" "") + (match_operand:SF 5 "nonimmediate_operand" "")]) + (match_operand:SF 2 "nonmemory_operand" "") + (match_operand:SF 3 "nonmemory_operand" "")))] + "SSE_REG_P (operands[0]) && reload_completed + && (const0_operand (operands[2], GET_MODE (operands[0])) + || const0_operand (operands[3], GET_MODE (operands[0])))" + [(set (match_dup 0) (match_op_dup 1 [(match_dup 0) (match_dup 5)])) + (set (match_dup 8) (and:V4SF (match_dup 6) (match_dup 7)))] +{ + PUT_MODE (operands[1], GET_MODE (operands[0])); + if (!sse_comparison_operator (operands[1], VOIDmode) + || !rtx_equal_p (operands[0], operands[4])) + { + rtx tmp = operands[5]; + operands[5] = operands[4]; + operands[4] = tmp; + PUT_CODE (operands[1], swap_condition (GET_CODE (operands[1]))); + } + if (!rtx_equal_p (operands[0], operands[4])) + abort (); + operands[8] = simplify_gen_subreg (V4SFmode, operands[0], SFmode, 0); + if (const0_operand (operands[2], GET_MODE (operands[2]))) + { + operands[7] = operands[3]; + operands[6] = gen_rtx_NOT (V4SFmode, operands[5]); + } + else + { + operands[7] = operands[2]; + operands[6] = operands[8]; + } + operands[7] = simplify_gen_subreg (V4SFmode, operands[7], SFmode, 0); +}) + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(match_operand:DF 4 "nonimmediate_operand" "") + (match_operand:DF 5 "nonimmediate_operand" "")]) + (match_operand:DF 2 "nonmemory_operand" "") + (match_operand:DF 3 "nonmemory_operand" "")))] + "SSE_REG_P (operands[0]) && reload_completed + && (const0_operand (operands[2], GET_MODE (operands[0])) + || const0_operand (operands[3], GET_MODE (operands[0])))" + [(set (match_dup 0) (match_op_dup 1 [(match_dup 0) (match_dup 5)])) + (set (match_dup 8) (and:V2DF (match_dup 6) (match_dup 7)))] +{ + if (TARGET_SSE_PARTIAL_REGS && !optimize_size + && GET_MODE (operands[2]) == DFmode) + { + if (REG_P (operands[2])) + { + rtx op = simplify_gen_subreg (V2DFmode, operands[2], DFmode, 0); + emit_insn (gen_sse2_unpcklpd (op, op, op)); + } + if (REG_P (operands[3])) + { + rtx op = simplify_gen_subreg (V2DFmode, operands[3], DFmode, 0); + emit_insn (gen_sse2_unpcklpd (op, op, op)); + } + } + PUT_MODE (operands[1], GET_MODE (operands[0])); + if (!sse_comparison_operator (operands[1], VOIDmode) + || !rtx_equal_p (operands[0], operands[4])) + { + rtx tmp = operands[5]; + operands[5] = operands[4]; + operands[4] = tmp; + PUT_CODE (operands[1], swap_condition (GET_CODE (operands[1]))); + } + if (!rtx_equal_p (operands[0], operands[4])) + abort (); + operands[8] = simplify_gen_subreg (V2DFmode, operands[0], DFmode, 0); + if (const0_operand (operands[2], GET_MODE (operands[2]))) + { + operands[7] = operands[3]; + operands[6] = gen_rtx_NOT (V2DFmode, operands[8]); + } + else + { + operands[7] = operands[2]; + operands[6] = operands[8]; + } + operands[7] = simplify_gen_subreg (V2DFmode, operands[7], DFmode, 0); +}) + (define_expand "allocate_stack_worker" [(match_operand:SI 0 "register_operand" "")] "TARGET_STACK_PROBE" @@ -19402,9 +17353,9 @@ (define_insn "allocate_stack_worker_1" [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "a")] UNSPECV_STACK_PROBE) - (set (reg:SI SP_REG) (minus:SI (reg:SI SP_REG) (match_dup 0))) + (set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 0))) (clobber (match_scratch:SI 1 "=0")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "!TARGET_64BIT && TARGET_STACK_PROBE" "call\t__alloca" [(set_attr "type" "multi") @@ -19413,18 +17364,18 @@ (define_expand "allocate_stack_worker_postreload" [(parallel [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "a")] UNSPECV_STACK_PROBE) - (set (reg:SI SP_REG) (minus:SI (reg:SI SP_REG) (match_dup 0))) + (set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 0))) (clobber (match_dup 0)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") (define_insn "allocate_stack_worker_rex64" [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "a")] UNSPECV_STACK_PROBE) - (set (reg:DI SP_REG) (minus:DI (reg:DI SP_REG) (match_dup 0))) + (set (reg:DI 7) (minus:DI (reg:DI 7) (match_dup 0))) (clobber (match_scratch:DI 1 "=0")) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "TARGET_64BIT && TARGET_STACK_PROBE" "call\t__alloca" [(set_attr "type" "multi") @@ -19433,20 +17384,20 @@ (define_expand "allocate_stack_worker_rex64_postreload" [(parallel [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "a")] UNSPECV_STACK_PROBE) - (set (reg:DI SP_REG) (minus:DI (reg:DI SP_REG) (match_dup 0))) + (set (reg:DI 7) (minus:DI (reg:DI 7) (match_dup 0))) (clobber (match_dup 0)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "" "") (define_expand "allocate_stack" [(parallel [(set (match_operand:SI 0 "register_operand" "=r") - (minus:SI (reg:SI SP_REG) + (minus:SI (reg:SI 7) (match_operand:SI 1 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (parallel [(set (reg:SI SP_REG) - (minus:SI (reg:SI SP_REG) (match_dup 1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))]) + (parallel [(set (reg:SI 7) + (minus:SI (reg:SI 7) (match_dup 1))) + (clobber (reg:CC 17))])] "TARGET_STACK_PROBE" { #ifdef CHECK_STACK_LIMIT @@ -19467,21 +17418,7 @@ [(label_ref (match_operand 0 "" ""))] "!TARGET_64BIT && flag_pic" { - if (TARGET_MACHO) - { - rtx xops[3]; - rtx picreg = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); - rtx label_rtx = gen_label_rtx (); - emit_insn (gen_set_got_labelled (pic_offset_table_rtx, label_rtx)); - xops[0] = xops[1] = picreg; - xops[2] = gen_rtx_CONST (SImode, - gen_rtx_MINUS (SImode, - gen_rtx_LABEL_REF (SImode, label_rtx), - gen_rtx_SYMBOL_REF (SImode, GOT_SYMBOL_NAME))); - ix86_expand_binary_operator (MINUS, SImode, xops); - } - else - emit_insn (gen_set_got (pic_offset_table_rtx)); + emit_insn (gen_set_got (pic_offset_table_rtx)); DONE; }) @@ -19492,18 +17429,17 @@ (match_operator 3 "promotable_binary_operator" [(match_operand 1 "register_operand" "") (match_operand 2 "aligned_operand" "")])) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "! TARGET_PARTIAL_REG_STALL && reload_completed && ((GET_MODE (operands[0]) == HImode && ((!optimize_size && !TARGET_FAST_PREFIX) - /* ??? next two lines just !satisfies_constraint_K (...) */ || GET_CODE (operands[2]) != CONST_INT - || satisfies_constraint_K (operands[2]))) + || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))) || (GET_MODE (operands[0]) == QImode && (TARGET_PROMOTE_QImode || optimize_size)))" [(parallel [(set (match_dup 0) (match_op_dup 3 [(match_dup 1) (match_dup 2)])) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[0] = gen_lowpart (SImode, operands[0]); operands[1] = gen_lowpart (SImode, operands[1]); if (GET_CODE (operands[3]) != ASHIFT) @@ -19569,14 +17505,14 @@ (define_split [(set (match_operand 0 "register_operand" "") (neg (match_operand 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + (clobber (reg:CC 17))] "! TARGET_PARTIAL_REG_STALL && reload_completed && (GET_MODE (operands[0]) == HImode || (GET_MODE (operands[0]) == QImode && (TARGET_PROMOTE_QImode || optimize_size)))" [(parallel [(set (match_dup 0) (neg:SI (match_dup 1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[0] = gen_lowpart (SImode, operands[0]); operands[1] = gen_lowpart (SImode, operands[1]);") @@ -19595,7 +17531,7 @@ (define_split [(set (match_operand 0 "register_operand" "") (if_then_else (match_operator 1 "comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) + [(reg 17) (const_int 0)]) (match_operand 2 "register_operand" "") (match_operand 3 "register_operand" "")))] "! TARGET_PARTIAL_REG_STALL && TARGET_CMOVE @@ -19617,8 +17553,7 @@ [(set (match_operand:SI 0 "push_operand" "") (match_operand:SI 1 "memory_operand" "")) (match_scratch:SI 2 "r")] - "!optimize_size && !TARGET_PUSH_MEMORY - && !RTX_FRAME_RELATED_P (peep2_next_insn (0))" + "! optimize_size && ! TARGET_PUSH_MEMORY" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (match_dup 2))] "") @@ -19627,8 +17562,7 @@ [(set (match_operand:DI 0 "push_operand" "") (match_operand:DI 1 "memory_operand" "")) (match_scratch:DI 2 "r")] - "!optimize_size && !TARGET_PUSH_MEMORY - && !RTX_FRAME_RELATED_P (peep2_next_insn (0))" + "! optimize_size && ! TARGET_PUSH_MEMORY" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (match_dup 2))] "") @@ -19639,8 +17573,7 @@ [(set (match_operand:SF 0 "push_operand" "") (match_operand:SF 1 "memory_operand" "")) (match_scratch:SF 2 "r")] - "!optimize_size && !TARGET_PUSH_MEMORY - && !RTX_FRAME_RELATED_P (peep2_next_insn (0))" + "! optimize_size && ! TARGET_PUSH_MEMORY" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (match_dup 2))] "") @@ -19649,8 +17582,7 @@ [(set (match_operand:HI 0 "push_operand" "") (match_operand:HI 1 "memory_operand" "")) (match_scratch:HI 2 "r")] - "!optimize_size && !TARGET_PUSH_MEMORY - && !RTX_FRAME_RELATED_P (peep2_next_insn (0))" + "! optimize_size && ! TARGET_PUSH_MEMORY" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (match_dup 2))] "") @@ -19659,8 +17591,7 @@ [(set (match_operand:QI 0 "push_operand" "") (match_operand:QI 1 "memory_operand" "")) (match_scratch:QI 2 "q")] - "!optimize_size && !TARGET_PUSH_MEMORY - && !RTX_FRAME_RELATED_P (peep2_next_insn (0))" + "! optimize_size && ! TARGET_PUSH_MEMORY" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (match_dup 2))] "") @@ -19677,7 +17608,7 @@ && get_attr_length (insn) >= ix86_cost->large_insn && peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (match_dup 1) (const_int 0)) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (set (match_dup 0) (match_dup 1))] "") @@ -19691,7 +17622,7 @@ && get_attr_length (insn) >= ix86_cost->large_insn && peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (match_dup 2) (const_int 0)) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (set (match_dup 0) (match_dup 1))] "operands[2] = gen_lowpart (SImode, operands[1]);") @@ -19705,7 +17636,7 @@ && get_attr_length (insn) >= ix86_cost->large_insn && peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (match_dup 2) (const_int 0)) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (set (match_dup 0) (match_dup 1))] "operands[2] = gen_lowpart (SImode, operands[1]);") @@ -19756,7 +17687,7 @@ ;; Don't split NOTs with a displacement operand, because resulting XOR ;; will not be pairable anyway. ;; -;; On AMD K6, NOT is vector decoded with memory operand that cannot be +;; On AMD K6, NOT is vector decoded with memory operand that can not be ;; represented using a modRM byte. The XOR replacement is long decoded, ;; so this split helps here as well. ;; @@ -19774,7 +17705,7 @@ || (TARGET_K6 && long_memory_operand (operands[0], SImode)))" [(parallel [(set (match_dup 0) (xor:SI (match_dup 1) (const_int -1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_peephole2 @@ -19788,7 +17719,7 @@ || (TARGET_K6 && long_memory_operand (operands[0], HImode)))" [(parallel [(set (match_dup 0) (xor:HI (match_dup 1) (const_int -1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_peephole2 @@ -19802,7 +17733,7 @@ || (TARGET_K6 && long_memory_operand (operands[0], QImode)))" [(parallel [(set (match_dup 0) (xor:QI (match_dup 1) (const_int -1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") ;; Non pairable "test imm, reg" instructions can be translated to @@ -19820,7 +17751,8 @@ (const_int 0)]))] "ix86_match_ccmode (insn, CCNOmode) && (true_regnum (operands[2]) != 0 - || satisfies_constraint_K (operands[3])) + || (GET_CODE (operands[3]) == CONST_INT + && CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'K'))) && peep2_reg_dead_p (1, operands[2])" [(parallel [(set (match_dup 0) @@ -19892,12 +17824,12 @@ (match_operator:SI 3 "arith_or_logical_operator" [(match_dup 0) (match_operand:SI 1 "memory_operand" "")])) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "! optimize_size && ! TARGET_READ_MODIFY" [(set (match_dup 2) (match_dup 1)) (parallel [(set (match_dup 0) (match_op_dup 3 [(match_dup 0) (match_dup 2)])) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_peephole2 @@ -19906,12 +17838,12 @@ (match_operator:SI 3 "arith_or_logical_operator" [(match_operand:SI 1 "memory_operand" "") (match_dup 0)])) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "! optimize_size && ! TARGET_READ_MODIFY" [(set (match_dup 2) (match_dup 1)) (parallel [(set (match_dup 0) (match_op_dup 3 [(match_dup 2) (match_dup 0)])) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") ; Don't do logical operations with memory outputs @@ -19926,12 +17858,12 @@ (match_operator:SI 3 "arith_or_logical_operator" [(match_dup 0) (match_operand:SI 1 "nonmemory_operand" "")])) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "! optimize_size && ! TARGET_READ_MODIFY_WRITE" [(set (match_dup 2) (match_dup 0)) (parallel [(set (match_dup 2) (match_op_dup 3 [(match_dup 2) (match_dup 1)])) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (set (match_dup 0) (match_dup 2))] "") @@ -19941,28 +17873,29 @@ (match_operator:SI 3 "arith_or_logical_operator" [(match_operand:SI 1 "nonmemory_operand" "") (match_dup 0)])) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "! optimize_size && ! TARGET_READ_MODIFY_WRITE" [(set (match_dup 2) (match_dup 0)) (parallel [(set (match_dup 2) (match_op_dup 3 [(match_dup 1) (match_dup 2)])) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (set (match_dup 0) (match_dup 2))] "") ;; Attempt to always use XOR for zeroing registers. (define_peephole2 [(set (match_operand 0 "register_operand" "") - (match_operand 1 "const0_operand" ""))] - "GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD + (const_int 0))] + "(GET_MODE (operands[0]) == QImode + || GET_MODE (operands[0]) == HImode + || GET_MODE (operands[0]) == SImode + || (GET_MODE (operands[0]) == DImode && TARGET_64BIT)) && (! TARGET_USE_MOV0 || optimize_size) - && GENERAL_REG_P (operands[0]) && peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (match_dup 0) (const_int 0)) - (clobber (reg:CC FLAGS_REG))])] -{ - operands[0] = gen_lowpart (word_mode, operands[0]); -}) + (clobber (reg:CC 17))])] + "operands[0] = gen_lowpart (GET_MODE (operands[0]) == DImode ? DImode : SImode, + operands[0]);") (define_peephole2 [(set (strict_low_part (match_operand 0 "register_operand" "")) @@ -19972,7 +17905,7 @@ && (! TARGET_USE_MOV0 || optimize_size) && peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (strict_low_part (match_dup 0)) (const_int 0)) - (clobber (reg:CC FLAGS_REG))])]) + (clobber (reg:CC 17))])]) ;; For HI and SI modes, or $-1,reg is smaller than mov $-1,reg. (define_peephole2 @@ -19984,7 +17917,7 @@ && (optimize_size || TARGET_PENTIUM) && peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (match_dup 0) (const_int -1)) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[0] = gen_lowpart (GET_MODE (operands[0]) == DImode ? DImode : SImode, operands[0]);") @@ -19996,7 +17929,7 @@ (match_operand:SI 1 "nonmemory_operand" "")))] "peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_peephole2 @@ -20005,7 +17938,7 @@ (match_operand:DI 2 "nonmemory_operand" "")) 0))] "peep2_regno_dead_p (0, FLAGS_REG) && REGNO (operands[0]) == REGNO (operands[1])" [(parallel [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[2] = gen_lowpart (SImode, operands[2]);") (define_peephole2 @@ -20014,7 +17947,7 @@ (match_operand:DI 1 "x86_64_general_operand" "")))] "peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_peephole2 @@ -20024,7 +17957,7 @@ "exact_log2 (INTVAL (operands[1])) >= 0 && peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1])));") (define_peephole2 @@ -20034,7 +17967,7 @@ "exact_log2 (INTVAL (operands[1])) >= 0 && peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (match_dup 0) (ashift:DI (match_dup 0) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1])));") (define_peephole2 @@ -20045,7 +17978,7 @@ && REGNO (operands[0]) == REGNO (operands[1]) && peep2_regno_dead_p (0, FLAGS_REG)" [(parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "operands[2] = GEN_INT (exact_log2 (INTVAL (operands[2])));") ;; The ESP adjustments can be done by the push and pop instructions. Resulting @@ -20069,52 +18002,52 @@ (define_peephole2 [(match_scratch:SI 0 "r") - (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) - (clobber (reg:CC FLAGS_REG)) + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -4))) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))])] "optimize_size || !TARGET_SUB_ESP_4" [(clobber (match_dup 0)) - (parallel [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0)) + (parallel [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0)) (clobber (mem:BLK (scratch)))])]) (define_peephole2 [(match_scratch:SI 0 "r") - (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -8))) - (clobber (reg:CC FLAGS_REG)) + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))])] "optimize_size || !TARGET_SUB_ESP_8" [(clobber (match_dup 0)) - (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0)) - (parallel [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0)) + (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0)) + (parallel [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0)) (clobber (mem:BLK (scratch)))])]) ;; Convert esp subtractions to push. (define_peephole2 [(match_scratch:SI 0 "r") - (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) - (clobber (reg:CC FLAGS_REG))])] + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -4))) + (clobber (reg:CC 17))])] "optimize_size || !TARGET_SUB_ESP_4" [(clobber (match_dup 0)) - (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))]) + (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))]) (define_peephole2 [(match_scratch:SI 0 "r") - (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -8))) - (clobber (reg:CC FLAGS_REG))])] + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (clobber (reg:CC 17))])] "optimize_size || !TARGET_SUB_ESP_8" [(clobber (match_dup 0)) - (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0)) - (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))]) + (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0)) + (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))]) ;; Convert epilogue deallocator to pop. (define_peephole2 [(match_scratch:SI 0 "r") - (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4))) - (clobber (reg:CC FLAGS_REG)) + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4))) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))])] "optimize_size || !TARGET_ADD_ESP_4" - [(parallel [(set (match_dup 0) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4))) + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4))) (clobber (mem:BLK (scratch)))])] "") @@ -20123,38 +18056,38 @@ (define_peephole2 [(match_scratch:SI 0 "r") (match_scratch:SI 1 "r") - (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 8))) - (clobber (reg:CC FLAGS_REG)) + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8))) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))])] "optimize_size || !TARGET_ADD_ESP_8" - [(parallel [(set (match_dup 0) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4))) + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4))) (clobber (mem:BLK (scratch)))]) - (parallel [(set (match_dup 1) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))])] + (parallel [(set (match_dup 1) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] "") (define_peephole2 [(match_scratch:SI 0 "r") - (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 8))) - (clobber (reg:CC FLAGS_REG)) + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8))) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))])] "optimize_size" - [(parallel [(set (match_dup 0) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4))) + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4))) (clobber (mem:BLK (scratch)))]) - (parallel [(set (match_dup 0) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))])] + (parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] "") ;; Convert esp additions to pop. (define_peephole2 [(match_scratch:SI 0 "r") - (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4))) - (clobber (reg:CC FLAGS_REG))])] + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4))) + (clobber (reg:CC 17))])] "" - [(parallel [(set (match_dup 0) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))])] + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] "") ;; Two pops case is tricky, since pop causes dependency on destination register. @@ -20162,24 +18095,24 @@ (define_peephole2 [(match_scratch:SI 0 "r") (match_scratch:SI 1 "r") - (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 8))) - (clobber (reg:CC FLAGS_REG))])] + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8))) + (clobber (reg:CC 17))])] "" - [(parallel [(set (match_dup 0) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))]) - (parallel [(set (match_dup 1) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))])] + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))]) + (parallel [(set (match_dup 1) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] "") (define_peephole2 [(match_scratch:SI 0 "r") - (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 8))) - (clobber (reg:CC FLAGS_REG))])] + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8))) + (clobber (reg:CC 17))])] "optimize_size" - [(parallel [(set (match_dup 0) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))]) - (parallel [(set (match_dup 0) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))])] + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))]) + (parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] "") ;; Convert compares with 1 to shorter inc/dec operations when CF is not @@ -20201,52 +18134,52 @@ (define_peephole2 [(match_scratch:DI 0 "r") - (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -8))) - (clobber (reg:CC FLAGS_REG)) + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -8))) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))])] "optimize_size || !TARGET_SUB_ESP_4" [(clobber (match_dup 0)) - (parallel [(set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0)) + (parallel [(set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0)) (clobber (mem:BLK (scratch)))])]) (define_peephole2 [(match_scratch:DI 0 "r") - (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -16))) - (clobber (reg:CC FLAGS_REG)) + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -16))) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))])] "optimize_size || !TARGET_SUB_ESP_8" [(clobber (match_dup 0)) - (set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0)) - (parallel [(set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0)) + (set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0)) + (parallel [(set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0)) (clobber (mem:BLK (scratch)))])]) ;; Convert esp subtractions to push. (define_peephole2 [(match_scratch:DI 0 "r") - (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -8))) - (clobber (reg:CC FLAGS_REG))])] + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -8))) + (clobber (reg:CC 17))])] "optimize_size || !TARGET_SUB_ESP_4" [(clobber (match_dup 0)) - (set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0))]) + (set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0))]) (define_peephole2 [(match_scratch:DI 0 "r") - (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -16))) - (clobber (reg:CC FLAGS_REG))])] + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -16))) + (clobber (reg:CC 17))])] "optimize_size || !TARGET_SUB_ESP_8" [(clobber (match_dup 0)) - (set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0)) - (set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0))]) + (set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0)) + (set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0))]) ;; Convert epilogue deallocator to pop. (define_peephole2 [(match_scratch:DI 0 "r") - (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8))) - (clobber (reg:CC FLAGS_REG)) + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8))) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))])] "optimize_size || !TARGET_ADD_ESP_4" - [(parallel [(set (match_dup 0) (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8))) + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8))) (clobber (mem:BLK (scratch)))])] "") @@ -20255,38 +18188,38 @@ (define_peephole2 [(match_scratch:DI 0 "r") (match_scratch:DI 1 "r") - (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 16))) - (clobber (reg:CC FLAGS_REG)) + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 16))) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))])] "optimize_size || !TARGET_ADD_ESP_8" - [(parallel [(set (match_dup 0) (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8))) + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8))) (clobber (mem:BLK (scratch)))]) - (parallel [(set (match_dup 1) (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8)))])] + (parallel [(set (match_dup 1) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))])] "") (define_peephole2 [(match_scratch:DI 0 "r") - (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 16))) - (clobber (reg:CC FLAGS_REG)) + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 16))) + (clobber (reg:CC 17)) (clobber (mem:BLK (scratch)))])] "optimize_size" - [(parallel [(set (match_dup 0) (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8))) + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8))) (clobber (mem:BLK (scratch)))]) - (parallel [(set (match_dup 0) (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8)))])] + (parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))])] "") ;; Convert esp additions to pop. (define_peephole2 [(match_scratch:DI 0 "r") - (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8))) - (clobber (reg:CC FLAGS_REG))])] + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8))) + (clobber (reg:CC 17))])] "" - [(parallel [(set (match_dup 0) (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8)))])] + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))])] "") ;; Two pops case is tricky, since pop causes dependency on destination register. @@ -20294,89 +18227,26 @@ (define_peephole2 [(match_scratch:DI 0 "r") (match_scratch:DI 1 "r") - (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 16))) - (clobber (reg:CC FLAGS_REG))])] + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 16))) + (clobber (reg:CC 17))])] "" - [(parallel [(set (match_dup 0) (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8)))]) - (parallel [(set (match_dup 1) (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8)))])] + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))]) + (parallel [(set (match_dup 1) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))])] "") (define_peephole2 [(match_scratch:DI 0 "r") - (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 16))) - (clobber (reg:CC FLAGS_REG))])] + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 16))) + (clobber (reg:CC 17))])] "optimize_size" - [(parallel [(set (match_dup 0) (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8)))]) - (parallel [(set (match_dup 0) (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8)))])] + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))]) + (parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))])] "") -;; Convert imul by three, five and nine into lea -(define_peephole2 - [(parallel - [(set (match_operand:SI 0 "register_operand" "") - (mult:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "INTVAL (operands[2]) == 3 - || INTVAL (operands[2]) == 5 - || INTVAL (operands[2]) == 9" - [(set (match_dup 0) - (plus:SI (mult:SI (match_dup 1) (match_dup 2)) - (match_dup 1)))] - { operands[2] = GEN_INT (INTVAL (operands[2]) - 1); }) - -(define_peephole2 - [(parallel - [(set (match_operand:SI 0 "register_operand" "") - (mult:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:SI 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "!optimize_size - && (INTVAL (operands[2]) == 3 - || INTVAL (operands[2]) == 5 - || INTVAL (operands[2]) == 9)" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) - (plus:SI (mult:SI (match_dup 0) (match_dup 2)) - (match_dup 0)))] - { operands[2] = GEN_INT (INTVAL (operands[2]) - 1); }) - -(define_peephole2 - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (mult:DI (match_operand:DI 1 "register_operand" "") - (match_operand:DI 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT - && (INTVAL (operands[2]) == 3 - || INTVAL (operands[2]) == 5 - || INTVAL (operands[2]) == 9)" - [(set (match_dup 0) - (plus:DI (mult:DI (match_dup 1) (match_dup 2)) - (match_dup 1)))] - { operands[2] = GEN_INT (INTVAL (operands[2]) - 1); }) - -(define_peephole2 - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (mult:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT - && !optimize_size - && (INTVAL (operands[2]) == 3 - || INTVAL (operands[2]) == 5 - || INTVAL (operands[2]) == 9)" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) - (plus:DI (mult:DI (match_dup 0) (match_dup 2)) - (match_dup 0)))] - { operands[2] = GEN_INT (INTVAL (operands[2]) - 1); }) - ;; Imul $32bit_imm, mem, reg is vector decoded, while ;; imul $32bit_imm, reg, reg is direct decoded. (define_peephole2 @@ -20384,12 +18254,13 @@ (parallel [(set (match_operand:DI 0 "register_operand" "") (mult:DI (match_operand:DI 1 "memory_operand" "") (match_operand:DI 2 "immediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size - && !satisfies_constraint_K (operands[2])" + (clobber (reg:CC 17))])] + "TARGET_K8 && !optimize_size + && (GET_CODE (operands[2]) != CONST_INT + || !CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))" [(set (match_dup 3) (match_dup 1)) (parallel [(set (match_dup 0) (mult:DI (match_dup 3) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_peephole2 @@ -20397,12 +18268,13 @@ (parallel [(set (match_operand:SI 0 "register_operand" "") (mult:SI (match_operand:SI 1 "memory_operand" "") (match_operand:SI 2 "immediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size - && !satisfies_constraint_K (operands[2])" + (clobber (reg:CC 17))])] + "TARGET_K8 && !optimize_size + && (GET_CODE (operands[2]) != CONST_INT + || !CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))" [(set (match_dup 3) (match_dup 1)) (parallel [(set (match_dup 0) (mult:SI (match_dup 3) (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") (define_peephole2 @@ -20411,12 +18283,13 @@ (zero_extend:DI (mult:SI (match_operand:SI 1 "memory_operand" "") (match_operand:SI 2 "immediate_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] - "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size - && !satisfies_constraint_K (operands[2])" + (clobber (reg:CC 17))])] + "TARGET_K8 && !optimize_size + && (GET_CODE (operands[2]) != CONST_INT + || !CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))" [(set (match_dup 3) (match_dup 1)) (parallel [(set (match_dup 0) (zero_extend:DI (mult:SI (match_dup 3) (match_dup 2)))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] "") ;; imul $8/16bit_imm, regmem, reg is vector decoded. @@ -20427,13 +18300,13 @@ [(parallel [(set (match_operand:DI 0 "register_operand" "") (mult:DI (match_operand:DI 1 "nonimmediate_operand" "") (match_operand:DI 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (match_scratch:DI 3 "r")] - "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size - && satisfies_constraint_K (operands[2])" + "TARGET_K8 && !optimize_size + && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')" [(set (match_dup 3) (match_dup 2)) (parallel [(set (match_dup 0) (mult:DI (match_dup 0) (match_dup 3))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] { if (!rtx_equal_p (operands[0], operands[1])) emit_move_insn (operands[0], operands[1]); @@ -20443,13 +18316,13 @@ [(parallel [(set (match_operand:SI 0 "register_operand" "") (mult:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:SI 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (match_scratch:SI 3 "r")] - "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size - && satisfies_constraint_K (operands[2])" + "TARGET_K8 && !optimize_size + && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')" [(set (match_dup 3) (match_dup 2)) (parallel [(set (match_dup 0) (mult:SI (match_dup 0) (match_dup 3))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] { if (!rtx_equal_p (operands[0], operands[1])) emit_move_insn (operands[0], operands[1]); @@ -20459,74 +18332,16 @@ [(parallel [(set (match_operand:HI 0 "register_operand" "") (mult:HI (match_operand:HI 1 "nonimmediate_operand" "") (match_operand:HI 2 "immediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) + (clobber (reg:CC 17))]) (match_scratch:HI 3 "r")] - "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size" + "TARGET_K8 && !optimize_size" [(set (match_dup 3) (match_dup 2)) (parallel [(set (match_dup 0) (mult:HI (match_dup 0) (match_dup 3))) - (clobber (reg:CC FLAGS_REG))])] + (clobber (reg:CC 17))])] { if (!rtx_equal_p (operands[0], operands[1])) emit_move_insn (operands[0], operands[1]); }) - -;; After splitting up read-modify operations, array accesses with memory -;; operands might end up in form: -;; sall $2, %eax -;; movl 4(%esp), %edx -;; addl %edx, %eax -;; instead of pre-splitting: -;; sall $2, %eax -;; addl 4(%esp), %eax -;; Turn it into: -;; movl 4(%esp), %edx -;; leal (%edx,%eax,4), %eax - -(define_peephole2 - [(parallel [(set (match_operand 0 "register_operand" "") - (ashift (match_operand 1 "register_operand" "") - (match_operand 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (set (match_operand 3 "register_operand") - (match_operand 4 "x86_64_general_operand" "")) - (parallel [(set (match_operand 5 "register_operand" "") - (plus (match_operand 6 "register_operand" "") - (match_operand 7 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) <= 3 - /* Validate MODE for lea. */ - && ((!TARGET_PARTIAL_REG_STALL - && (GET_MODE (operands[0]) == QImode - || GET_MODE (operands[0]) == HImode)) - || GET_MODE (operands[0]) == SImode - || (TARGET_64BIT && GET_MODE (operands[0]) == DImode)) - /* We reorder load and the shift. */ - && !rtx_equal_p (operands[1], operands[3]) - && !reg_overlap_mentioned_p (operands[0], operands[4]) - /* Last PLUS must consist of operand 0 and 3. */ - && !rtx_equal_p (operands[0], operands[3]) - && (rtx_equal_p (operands[3], operands[6]) - || rtx_equal_p (operands[3], operands[7])) - && (rtx_equal_p (operands[0], operands[6]) - || rtx_equal_p (operands[0], operands[7])) - /* The intermediate operand 0 must die or be same as output. */ - && (rtx_equal_p (operands[0], operands[5]) - || peep2_reg_dead_p (3, operands[0]))" - [(set (match_dup 3) (match_dup 4)) - (set (match_dup 0) (match_dup 1))] -{ - enum machine_mode mode = GET_MODE (operands[5]) == DImode ? DImode : SImode; - int scale = 1 << INTVAL (operands[2]); - rtx index = gen_lowpart (Pmode, operands[1]); - rtx base = gen_lowpart (Pmode, operands[3]); - rtx dest = gen_lowpart (mode, operands[5]); - - operands[1] = gen_rtx_PLUS (Pmode, base, - gen_rtx_MULT (Pmode, index, GEN_INT (scale))); - if (mode != Pmode) - operands[1] = gen_rtx_SUBREG (mode, operands[1], 0); - operands[0] = dest; -}) ;; Call-value patterns last so that the wildcard operand does not ;; disrupt insn-recog's switch tables. @@ -20535,7 +18350,7 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:SI 1 "constant_call_address_operand" "")) (match_operand:SI 2 "" ""))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) + (set (reg:SI 7) (plus:SI (reg:SI 7) (match_operand:SI 3 "immediate_operand" "")))] "!TARGET_64BIT" { @@ -20550,11 +18365,11 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:SI 1 "call_insn_operand" "rsm")) (match_operand:SI 2 "" ""))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) + (set (reg:SI 7) (plus:SI (reg:SI 7) (match_operand:SI 3 "immediate_operand" "i")))] "!TARGET_64BIT" { - if (constant_call_address_operand (operands[1], Pmode)) + if (constant_call_address_operand (operands[1], QImode)) { if (SIBLING_CALL_P (insn)) return "jmp\t%P1"; @@ -20600,7 +18415,7 @@ (match_operand:SI 2 "" "")))] "!SIBLING_CALL_P (insn) && !TARGET_64BIT" { - if (constant_call_address_operand (operands[1], Pmode)) + if (constant_call_address_operand (operands[1], QImode)) return "call\t%P1"; return "call\t%A1"; } @@ -20612,7 +18427,7 @@ (match_operand:SI 2 "" "")))] "SIBLING_CALL_P (insn) && !TARGET_64BIT" { - if (constant_call_address_operand (operands[1], Pmode)) + if (constant_call_address_operand (operands[1], QImode)) return "jmp\t%P1"; return "jmp\t%A1"; } @@ -20624,7 +18439,7 @@ (match_operand:DI 2 "" "")))] "!SIBLING_CALL_P (insn) && TARGET_64BIT" { - if (constant_call_address_operand (operands[1], Pmode)) + if (constant_call_address_operand (operands[1], QImode)) return "call\t%P1"; return "call\t%A1"; } @@ -20646,16 +18461,2402 @@ "jmp\t*%%r11" [(set_attr "type" "callv")]) -;; We used to use "int $5", in honor of #BR which maps to interrupt vector 5. -;; That, however, is usually mapped by the OS to SIGSEGV, which is often -;; caught for use by garbage collectors and the like. Using an insn that -;; maps to SIGILL makes it more likely the program will rightfully die. -;; Keeping with tradition, "6" is in honor of #UD. (define_insn "trap" - [(trap_if (const_int 1) (const_int 6))] + [(trap_if (const_int 1) (const_int 5))] "" - { return ASM_SHORT "0x0b0f"; } - [(set_attr "length" "2")]) + "int\t$5") + +;;; ix86 doesn't have conditional trap instructions, but we fake them +;;; for the sake of bounds checking. By emitting bounds checks as +;;; conditional traps rather than as conditional jumps around +;;; unconditional traps we avoid introducing spurious basic-block +;;; boundaries and facilitate elimination of redundant checks. In +;;; honor of the too-inflexible-for-BPs `bound' instruction, we use +;;; interrupt 5. +;;; +;;; FIXME: Static branch prediction rules for ix86 are such that +;;; forward conditional branches predict as untaken. As implemented +;;; below, pseudo conditional traps violate that rule. We should use +;;; .pushsection/.popsection to place all of the `int 5's in a special +;;; section loaded at the end of the text segment and branch forward +;;; there on bounds-failure, and then jump back immediately (in case +;;; the system chooses to ignore bounds violations, or to report +;;; violations and continue execution). + +(define_expand "conditional_trap" + [(trap_if (match_operator 0 "comparison_operator" + [(match_dup 2) (const_int 0)]) + (match_operand 1 "const_int_operand" ""))] + "" +{ + emit_insn (gen_rtx_TRAP_IF (VOIDmode, + ix86_expand_compare (GET_CODE (operands[0]), + NULL, NULL), + operands[1])); + DONE; +}) + +(define_insn "*conditional_trap_1" + [(trap_if (match_operator 0 "comparison_operator" + [(reg 17) (const_int 0)]) + (match_operand 1 "const_int_operand" ""))] + "" +{ + operands[2] = gen_label_rtx (); + output_asm_insn ("j%c0\t%l2\; int\t%1", operands); + (*targetm.asm_out.internal_label) (asm_out_file, "L", + CODE_LABEL_NUMBER (operands[2])); + RET; +}) + + ;; Pentium III SIMD instructions. + +;; Moves for SSE/MMX regs. + +(define_insn "*movv4sf_internal" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,x,m") + (match_operand:V4SF 1 "vector_move_operand" "C,xm,x"))] + "TARGET_SSE + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "@ + xorps\t%0, %0 + movaps\t{%1, %0|%0, %1} + movaps\t{%1, %0|%0, %1}" + [(set_attr "type" "ssemov") + (set_attr "mode" "V4SF")]) + +(define_split + [(set (match_operand:V4SF 0 "register_operand" "") + (match_operand:V4SF 1 "zero_extended_scalar_load_operand" ""))] + "TARGET_SSE && reload_completed" + [(set (match_dup 0) + (vec_merge:V4SF + (vec_duplicate:V4SF (match_dup 1)) + (match_dup 2) + (const_int 1)))] +{ + operands[1] = simplify_gen_subreg (SFmode, operands[1], V4SFmode, 0); + operands[2] = CONST0_RTX (V4SFmode); +}) + +(define_insn "*movv4si_internal" + [(set (match_operand:V4SI 0 "nonimmediate_operand" "=x,x,m") + (match_operand:V4SI 1 "vector_move_operand" "C,xm,x"))] + "TARGET_SSE + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: + if (get_attr_mode (insn) == MODE_V4SF) + return "xorps\t%0, %0"; + else + return "pxor\t%0, %0"; + case 1: + case 2: + if (get_attr_mode (insn) == MODE_V4SF) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movdqa\t{%1, %0|%0, %1}"; + default: + abort (); + } +} + [(set_attr "type" "ssemov") + (set (attr "mode") + (cond [(eq_attr "alternative" "0,1") + (if_then_else + (ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (const_string "TI")) + (eq_attr "alternative" "2") + (if_then_else + (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") + (const_int 0)) + (ne (symbol_ref "optimize_size") + (const_int 0))) + (const_string "V4SF") + (const_string "TI"))] + (const_string "TI")))]) + +(define_insn "*movv2di_internal" + [(set (match_operand:V2DI 0 "nonimmediate_operand" "=x,x,m") + (match_operand:V2DI 1 "vector_move_operand" "C,xm,x"))] + "TARGET_SSE + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: + if (get_attr_mode (insn) == MODE_V4SF) + return "xorps\t%0, %0"; + else + return "pxor\t%0, %0"; + case 1: + case 2: + if (get_attr_mode (insn) == MODE_V4SF) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movdqa\t{%1, %0|%0, %1}"; + default: + abort (); + } +} + [(set_attr "type" "ssemov") + (set (attr "mode") + (cond [(eq_attr "alternative" "0,1") + (if_then_else + (ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (const_string "TI")) + (eq_attr "alternative" "2") + (if_then_else + (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") + (const_int 0)) + (ne (symbol_ref "optimize_size") + (const_int 0))) + (const_string "V4SF") + (const_string "TI"))] + (const_string "TI")))]) + +(define_split + [(set (match_operand:V2DF 0 "register_operand" "") + (match_operand:V2DF 1 "zero_extended_scalar_load_operand" ""))] + "TARGET_SSE2 && reload_completed" + [(set (match_dup 0) + (vec_merge:V2DF + (vec_duplicate:V2DF (match_dup 1)) + (match_dup 2) + (const_int 1)))] +{ + operands[1] = simplify_gen_subreg (DFmode, operands[1], V2DFmode, 0); + operands[2] = CONST0_RTX (V2DFmode); +}) + +(define_insn "*movv2si_internal" + [(set (match_operand:V2SI 0 "nonimmediate_operand" + "=y,y ,m,!y,!*Y,*x,?*x,?m") + (match_operand:V2SI 1 "vector_move_operand" + "C ,ym,y,*Y,y ,C ,*xm,*x"))] + "TARGET_MMX + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "@ + pxor\t%0, %0 + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1} + movdq2q\t{%1, %0|%0, %1} + movq2dq\t{%1, %0|%0, %1} + pxor\t%0, %0 + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxmov,mmxmov,mmxmov,ssecvt,ssecvt,ssemov,ssemov,ssemov") + (set_attr "mode" "DI")]) + +(define_insn "*movv4hi_internal" + [(set (match_operand:V4HI 0 "nonimmediate_operand" + "=y,y ,m,!y,!*Y,*x,?*x,?m") + (match_operand:V4HI 1 "vector_move_operand" + "C ,ym,y,*Y,y ,C ,*xm,*x"))] + "TARGET_MMX + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "@ + pxor\t%0, %0 + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1} + movdq2q\t{%1, %0|%0, %1} + movq2dq\t{%1, %0|%0, %1} + pxor\t%0, %0 + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxmov,mmxmov,mmxmov,ssecvt,ssecvt,ssemov,ssemov,ssemov") + (set_attr "mode" "DI")]) + +(define_insn "*movv8qi_internal" + [(set (match_operand:V8QI 0 "nonimmediate_operand" + "=y,y ,m,!y,!*Y,*x,?*x,?m") + (match_operand:V8QI 1 "vector_move_operand" + "C ,ym,y,*Y,y ,C ,*xm,*x"))] + "TARGET_MMX + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "@ + pxor\t%0, %0 + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1} + movdq2q\t{%1, %0|%0, %1} + movq2dq\t{%1, %0|%0, %1} + pxor\t%0, %0 + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxmov,mmxmov,mmxmov,ssecvt,ssecvt,ssemov,ssemov,ssemov") + (set_attr "mode" "DI")]) + +(define_insn "*movv2sf_internal" + [(set (match_operand:V2SF 0 "nonimmediate_operand" + "=y,y ,m,!y,!*Y,*x,?*x,?m") + (match_operand:V2SF 1 "vector_move_operand" + "C ,ym,y,*Y,y ,C ,*xm,*x"))] + "TARGET_MMX + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "@ + pxor\t%0, %0 + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1} + movdq2q\t{%1, %0|%0, %1} + movq2dq\t{%1, %0|%0, %1} + xorps\t%0, %0 + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxmov,mmxmov,mmxmov,ssecvt,ssecvt,ssemov,ssemov,ssemov") + (set_attr "mode" "DI")]) + +(define_expand "movti" + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "nonimmediate_operand" ""))] + "TARGET_SSE || TARGET_64BIT" +{ + if (TARGET_64BIT) + ix86_expand_move (TImode, operands); + else + ix86_expand_vector_move (TImode, operands); + DONE; +}) + +(define_expand "movtf" + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (match_operand:TF 1 "nonimmediate_operand" ""))] + "TARGET_64BIT" +{ + ix86_expand_move (TFmode, operands); + DONE; +}) + +(define_insn "*movv2df_internal" + [(set (match_operand:V2DF 0 "nonimmediate_operand" "=x,x,m") + (match_operand:V2DF 1 "vector_move_operand" "C,xm,x"))] + "TARGET_SSE + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: + if (get_attr_mode (insn) == MODE_V4SF) + return "xorps\t%0, %0"; + else + return "xorpd\t%0, %0"; + case 1: + case 2: + if (get_attr_mode (insn) == MODE_V4SF) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movapd\t{%1, %0|%0, %1}"; + default: + abort (); + } +} + [(set_attr "type" "ssemov") + (set (attr "mode") + (cond [(eq (symbol_ref "TARGET_SSE2") (const_int 0)) + (const_string "V4SF") + (eq_attr "alternative" "0,1") + (if_then_else + (ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (const_string "V2DF")) + (eq_attr "alternative" "2") + (if_then_else + (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") + (const_int 0)) + (ne (symbol_ref "optimize_size") + (const_int 0))) + (const_string "V4SF") + (const_string "V2DF"))] + (const_string "V2DF")))]) + +(define_insn "*movv8hi_internal" + [(set (match_operand:V8HI 0 "nonimmediate_operand" "=x,x,m") + (match_operand:V8HI 1 "vector_move_operand" "C,xm,x"))] + "TARGET_SSE + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: + if (get_attr_mode (insn) == MODE_V4SF) + return "xorps\t%0, %0"; + else + return "pxor\t%0, %0"; + case 1: + case 2: + if (get_attr_mode (insn) == MODE_V4SF) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movdqa\t{%1, %0|%0, %1}"; + default: + abort (); + } +} + [(set_attr "type" "ssemov") + (set (attr "mode") + (cond [(eq_attr "alternative" "0,1") + (if_then_else + (ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (const_string "TI")) + (eq_attr "alternative" "2") + (if_then_else + (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") + (const_int 0)) + (ne (symbol_ref "optimize_size") + (const_int 0))) + (const_string "V4SF") + (const_string "TI"))] + (const_string "TI")))]) + +(define_insn "*movv16qi_internal" + [(set (match_operand:V16QI 0 "nonimmediate_operand" "=x,x,m") + (match_operand:V16QI 1 "vector_move_operand" "C,xm,x"))] + "TARGET_SSE + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: + if (get_attr_mode (insn) == MODE_V4SF) + return "xorps\t%0, %0"; + else + return "pxor\t%0, %0"; + case 1: + case 2: + if (get_attr_mode (insn) == MODE_V4SF) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movdqa\t{%1, %0|%0, %1}"; + default: + abort (); + } +} + [(set_attr "type" "ssemov") + (set (attr "mode") + (cond [(eq_attr "alternative" "0,1") + (if_then_else + (ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (const_string "TI")) + (eq_attr "alternative" "2") + (if_then_else + (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") + (const_int 0)) + (ne (symbol_ref "optimize_size") + (const_int 0))) + (const_string "V4SF") + (const_string "TI"))] + (const_string "TI")))]) + +(define_expand "movv2df" + [(set (match_operand:V2DF 0 "nonimmediate_operand" "") + (match_operand:V2DF 1 "nonimmediate_operand" ""))] + "TARGET_SSE" +{ + ix86_expand_vector_move (V2DFmode, operands); + DONE; +}) + +(define_expand "movv8hi" + [(set (match_operand:V8HI 0 "nonimmediate_operand" "") + (match_operand:V8HI 1 "nonimmediate_operand" ""))] + "TARGET_SSE" +{ + ix86_expand_vector_move (V8HImode, operands); + DONE; +}) + +(define_expand "movv16qi" + [(set (match_operand:V16QI 0 "nonimmediate_operand" "") + (match_operand:V16QI 1 "nonimmediate_operand" ""))] + "TARGET_SSE" +{ + ix86_expand_vector_move (V16QImode, operands); + DONE; +}) + +(define_expand "movv4sf" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "") + (match_operand:V4SF 1 "nonimmediate_operand" ""))] + "TARGET_SSE" +{ + ix86_expand_vector_move (V4SFmode, operands); + DONE; +}) + +(define_expand "movv4si" + [(set (match_operand:V4SI 0 "nonimmediate_operand" "") + (match_operand:V4SI 1 "nonimmediate_operand" ""))] + "TARGET_SSE" +{ + ix86_expand_vector_move (V4SImode, operands); + DONE; +}) + +(define_expand "movv2di" + [(set (match_operand:V2DI 0 "nonimmediate_operand" "") + (match_operand:V2DI 1 "nonimmediate_operand" ""))] + "TARGET_SSE" +{ + ix86_expand_vector_move (V2DImode, operands); + DONE; +}) + +(define_expand "movv2si" + [(set (match_operand:V2SI 0 "nonimmediate_operand" "") + (match_operand:V2SI 1 "nonimmediate_operand" ""))] + "TARGET_MMX" +{ + ix86_expand_vector_move (V2SImode, operands); + DONE; +}) + +(define_expand "movv4hi" + [(set (match_operand:V4HI 0 "nonimmediate_operand" "") + (match_operand:V4HI 1 "nonimmediate_operand" ""))] + "TARGET_MMX" +{ + ix86_expand_vector_move (V4HImode, operands); + DONE; +}) + +(define_expand "movv8qi" + [(set (match_operand:V8QI 0 "nonimmediate_operand" "") + (match_operand:V8QI 1 "nonimmediate_operand" ""))] + "TARGET_MMX" +{ + ix86_expand_vector_move (V8QImode, operands); + DONE; +}) + +(define_expand "movv2sf" + [(set (match_operand:V2SF 0 "nonimmediate_operand" "") + (match_operand:V2SF 1 "nonimmediate_operand" ""))] + "TARGET_MMX" +{ + ix86_expand_vector_move (V2SFmode, operands); + DONE; +}) + +(define_insn "*pushti" + [(set (match_operand:TI 0 "push_operand" "=<") + (match_operand:TI 1 "register_operand" "x"))] + "TARGET_SSE" + "#") + +(define_insn "*pushv2df" + [(set (match_operand:V2DF 0 "push_operand" "=<") + (match_operand:V2DF 1 "register_operand" "x"))] + "TARGET_SSE" + "#") + +(define_insn "*pushv2di" + [(set (match_operand:V2DI 0 "push_operand" "=<") + (match_operand:V2DI 1 "register_operand" "x"))] + "TARGET_SSE" + "#") + +(define_insn "*pushv8hi" + [(set (match_operand:V8HI 0 "push_operand" "=<") + (match_operand:V8HI 1 "register_operand" "x"))] + "TARGET_SSE" + "#") + +(define_insn "*pushv16qi" + [(set (match_operand:V16QI 0 "push_operand" "=<") + (match_operand:V16QI 1 "register_operand" "x"))] + "TARGET_SSE" + "#") + +(define_insn "*pushv4sf" + [(set (match_operand:V4SF 0 "push_operand" "=<") + (match_operand:V4SF 1 "register_operand" "x"))] + "TARGET_SSE" + "#") + +(define_insn "*pushv4si" + [(set (match_operand:V4SI 0 "push_operand" "=<") + (match_operand:V4SI 1 "register_operand" "x"))] + "TARGET_SSE" + "#") + +(define_insn "*pushv2si" + [(set (match_operand:V2SI 0 "push_operand" "=<") + (match_operand:V2SI 1 "register_operand" "y"))] + "TARGET_MMX" + "#") + +(define_insn "*pushv4hi" + [(set (match_operand:V4HI 0 "push_operand" "=<") + (match_operand:V4HI 1 "register_operand" "y"))] + "TARGET_MMX" + "#") + +(define_insn "*pushv8qi" + [(set (match_operand:V8QI 0 "push_operand" "=<") + (match_operand:V8QI 1 "register_operand" "y"))] + "TARGET_MMX" + "#") + +(define_insn "*pushv2sf" + [(set (match_operand:V2SF 0 "push_operand" "=<") + (match_operand:V2SF 1 "register_operand" "y"))] + "TARGET_MMX" + "#") + +(define_split + [(set (match_operand 0 "push_operand" "") + (match_operand 1 "register_operand" ""))] + "!TARGET_64BIT && reload_completed + && (SSE_REG_P (operands[1]) || MMX_REG_P (operands[1]))" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (match_dup 3))) + (set (match_dup 2) (match_dup 1))] + "operands[2] = change_address (operands[0], GET_MODE (operands[0]), + stack_pointer_rtx); + operands[3] = GEN_INT (-GET_MODE_SIZE (GET_MODE (operands[0])));") + +(define_split + [(set (match_operand 0 "push_operand" "") + (match_operand 1 "register_operand" ""))] + "TARGET_64BIT && reload_completed + && (SSE_REG_P (operands[1]) || MMX_REG_P (operands[1]))" + [(set (reg:DI 7) (plus:DI (reg:DI 7) (match_dup 3))) + (set (match_dup 2) (match_dup 1))] + "operands[2] = change_address (operands[0], GET_MODE (operands[0]), + stack_pointer_rtx); + operands[3] = GEN_INT (-GET_MODE_SIZE (GET_MODE (operands[0])));") + + +(define_insn "*movti_internal" + [(set (match_operand:TI 0 "nonimmediate_operand" "=x,x,m") + (match_operand:TI 1 "vector_move_operand" "C,xm,x"))] + "TARGET_SSE && !TARGET_64BIT + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: + if (get_attr_mode (insn) == MODE_V4SF) + return "xorps\t%0, %0"; + else + return "pxor\t%0, %0"; + case 1: + case 2: + if (get_attr_mode (insn) == MODE_V4SF) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movdqa\t{%1, %0|%0, %1}"; + default: + abort (); + } +} + [(set_attr "type" "ssemov,ssemov,ssemov") + (set (attr "mode") + (cond [(eq_attr "alternative" "0,1") + (if_then_else + (ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (const_string "TI")) + (eq_attr "alternative" "2") + (if_then_else + (ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (const_string "TI"))] + (const_string "TI")))]) + +(define_insn "*movti_rex64" + [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o,x,x,xm") + (match_operand:TI 1 "general_operand" "riFo,riF,C,xm,x"))] + "TARGET_64BIT + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: + case 1: + return "#"; + case 2: + if (get_attr_mode (insn) == MODE_V4SF) + return "xorps\t%0, %0"; + else + return "pxor\t%0, %0"; + case 3: + case 4: + if (get_attr_mode (insn) == MODE_V4SF) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movdqa\t{%1, %0|%0, %1}"; + default: + abort (); + } +} + [(set_attr "type" "*,*,ssemov,ssemov,ssemov") + (set (attr "mode") + (cond [(eq_attr "alternative" "2,3") + (if_then_else + (ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (const_string "TI")) + (eq_attr "alternative" "4") + (if_then_else + (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") + (const_int 0)) + (ne (symbol_ref "optimize_size") + (const_int 0))) + (const_string "V4SF") + (const_string "TI"))] + (const_string "DI")))]) + +(define_insn "*movtf_rex64" + [(set (match_operand:TF 0 "nonimmediate_operand" "=r,o,x,x,xm") + (match_operand:TF 1 "general_operand" "riFo,riF,C,xm,x"))] + "TARGET_64BIT + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: + case 1: + return "#"; + case 2: + if (get_attr_mode (insn) == MODE_V4SF) + return "xorps\t%0, %0"; + else + return "pxor\t%0, %0"; + case 3: + case 4: + if (get_attr_mode (insn) == MODE_V4SF) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movdqa\t{%1, %0|%0, %1}"; + default: + abort (); + } +} + [(set_attr "type" "*,*,ssemov,ssemov,ssemov") + (set (attr "mode") + (cond [(eq_attr "alternative" "2,3") + (if_then_else + (ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (const_string "TI")) + (eq_attr "alternative" "4") + (if_then_else + (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") + (const_int 0)) + (ne (symbol_ref "optimize_size") + (const_int 0))) + (const_string "V4SF") + (const_string "TI"))] + (const_string "DI")))]) + +(define_split + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "general_operand" ""))] + "reload_completed && !SSE_REG_P (operands[0]) + && !SSE_REG_P (operands[1])" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") + +(define_split + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (match_operand:TF 1 "general_operand" ""))] + "reload_completed && !SSE_REG_P (operands[0]) + && !SSE_REG_P (operands[1])" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") + +;; These two patterns are useful for specifying exactly whether to use +;; movaps or movups +(define_expand "sse_movaps" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "") + (unspec:V4SF [(match_operand:V4SF 1 "nonimmediate_operand" "")] + UNSPEC_MOVA))] + "TARGET_SSE" +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + { + rtx tmp = gen_reg_rtx (V4SFmode); + emit_insn (gen_sse_movaps (tmp, operands[1])); + emit_move_insn (operands[0], tmp); + DONE; + } +}) + +(define_insn "*sse_movaps_1" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,m") + (unspec:V4SF [(match_operand:V4SF 1 "nonimmediate_operand" "xm,x")] + UNSPEC_MOVA))] + "TARGET_SSE + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "movaps\t{%1, %0|%0, %1}" + [(set_attr "type" "ssemov,ssemov") + (set_attr "mode" "V4SF")]) + +(define_expand "sse_movups" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "") + (unspec:V4SF [(match_operand:V4SF 1 "nonimmediate_operand" "")] + UNSPEC_MOVU))] + "TARGET_SSE" +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + { + rtx tmp = gen_reg_rtx (V4SFmode); + emit_insn (gen_sse_movups (tmp, operands[1])); + emit_move_insn (operands[0], tmp); + DONE; + } +}) + +(define_insn "*sse_movups_1" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,m") + (unspec:V4SF [(match_operand:V4SF 1 "nonimmediate_operand" "xm,x")] + UNSPEC_MOVU))] + "TARGET_SSE + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "movups\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt,ssecvt") + (set_attr "mode" "V4SF")]) + +;; SSE Strange Moves. + +(define_insn "sse_movmskps" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:V4SF 1 "register_operand" "x")] + UNSPEC_MOVMSK))] + "TARGET_SSE" + "movmskps\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + +(define_insn "mmx_pmovmskb" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:V8QI 1 "register_operand" "y")] + UNSPEC_MOVMSK))] + "TARGET_SSE || TARGET_3DNOW_A" + "pmovmskb\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + + +(define_insn "mmx_maskmovq" + [(set (mem:V8QI (match_operand:SI 0 "register_operand" "D")) + (unspec:V8QI [(match_operand:V8QI 1 "register_operand" "y") + (match_operand:V8QI 2 "register_operand" "y")] + UNSPEC_MASKMOV))] + "(TARGET_SSE || TARGET_3DNOW_A) && !TARGET_64BIT" + ;; @@@ check ordering of operands in intel/nonintel syntax + "maskmovq\t{%2, %1|%1, %2}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + +(define_insn "mmx_maskmovq_rex" + [(set (mem:V8QI (match_operand:DI 0 "register_operand" "D")) + (unspec:V8QI [(match_operand:V8QI 1 "register_operand" "y") + (match_operand:V8QI 2 "register_operand" "y")] + UNSPEC_MASKMOV))] + "(TARGET_SSE || TARGET_3DNOW_A) && TARGET_64BIT" + ;; @@@ check ordering of operands in intel/nonintel syntax + "maskmovq\t{%2, %1|%1, %2}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + +(define_insn "sse_movntv4sf" + [(set (match_operand:V4SF 0 "memory_operand" "=m") + (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "x")] + UNSPEC_MOVNT))] + "TARGET_SSE" + "movntps\t{%1, %0|%0, %1}" + [(set_attr "type" "ssemov") + (set_attr "mode" "V4SF")]) + +(define_insn "sse_movntdi" + [(set (match_operand:DI 0 "memory_operand" "=m") + (unspec:DI [(match_operand:DI 1 "register_operand" "y")] + UNSPEC_MOVNT))] + "TARGET_SSE || TARGET_3DNOW_A" + "movntq\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxmov") + (set_attr "mode" "DI")]) + +(define_insn "sse_movhlps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0") + (vec_select:V4SF (match_operand:V4SF 2 "register_operand" "x") + (parallel [(const_int 2) + (const_int 3) + (const_int 0) + (const_int 1)])) + (const_int 3)))] + "TARGET_SSE" + "movhlps\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + +(define_insn "sse_movlhps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0") + (vec_select:V4SF (match_operand:V4SF 2 "register_operand" "x") + (parallel [(const_int 2) + (const_int 3) + (const_int 0) + (const_int 1)])) + (const_int 12)))] + "TARGET_SSE" + "movlhps\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + +(define_insn "sse_movhps" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,m") + (vec_merge:V4SF + (match_operand:V4SF 1 "nonimmediate_operand" "0,0") + (match_operand:V4SF 2 "nonimmediate_operand" "m,x") + (const_int 12)))] + "TARGET_SSE + && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM)" + "movhps\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + +(define_insn "sse_movlps" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,m") + (vec_merge:V4SF + (match_operand:V4SF 1 "nonimmediate_operand" "0,0") + (match_operand:V4SF 2 "nonimmediate_operand" "m,x") + (const_int 3)))] + "TARGET_SSE + && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM)" + "movlps\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + +(define_expand "sse_loadss" + [(match_operand:V4SF 0 "register_operand" "") + (match_operand:SF 1 "memory_operand" "")] + "TARGET_SSE" +{ + emit_insn (gen_sse_loadss_1 (operands[0], operands[1], + CONST0_RTX (V4SFmode))); + DONE; +}) + +(define_insn "sse_loadss_1" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (vec_duplicate:V4SF (match_operand:SF 1 "memory_operand" "m")) + (match_operand:V4SF 2 "const0_operand" "X") + (const_int 1)))] + "TARGET_SSE" + "movss\t{%1, %0|%0, %1}" + [(set_attr "type" "ssemov") + (set_attr "mode" "SF")]) + +(define_insn "sse_movss" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "register_operand" "x") + (const_int 1)))] + "TARGET_SSE" + "movss\t{%2, %0|%0, %2}" + [(set_attr "type" "ssemov") + (set_attr "mode" "SF")]) + +(define_insn "sse_storess" + [(set (match_operand:SF 0 "memory_operand" "=m") + (vec_select:SF + (match_operand:V4SF 1 "register_operand" "x") + (parallel [(const_int 0)])))] + "TARGET_SSE" + "movss\t{%1, %0|%0, %1}" + [(set_attr "type" "ssemov") + (set_attr "mode" "SF")]) + +(define_insn "sse_shufps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm") + (match_operand:SI 3 "immediate_operand" "i")] + UNSPEC_SHUFFLE))] + "TARGET_SSE" + ;; @@@ check operand order for intel/nonintel syntax + "shufps\t{%3, %2, %0|%0, %2, %3}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + + +;; SSE arithmetic + +(define_insn "addv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (plus:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "addps\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V4SF")]) + +(define_insn "vmaddv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (plus:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "addss\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "SF")]) + +(define_insn "subv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (minus:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "subps\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V4SF")]) + +(define_insn "vmsubv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (minus:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "subss\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "SF")]) + +(define_insn "mulv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (mult:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "mulps\t{%2, %0|%0, %2}" + [(set_attr "type" "ssemul") + (set_attr "mode" "V4SF")]) + +(define_insn "vmmulv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (mult:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "mulss\t{%2, %0|%0, %2}" + [(set_attr "type" "ssemul") + (set_attr "mode" "SF")]) + +(define_insn "divv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (div:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "divps\t{%2, %0|%0, %2}" + [(set_attr "type" "ssediv") + (set_attr "mode" "V4SF")]) + +(define_insn "vmdivv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (div:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "divss\t{%2, %0|%0, %2}" + [(set_attr "type" "ssediv") + (set_attr "mode" "SF")]) + + +;; SSE square root/reciprocal + +(define_insn "rcpv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF + [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] UNSPEC_RCP))] + "TARGET_SSE" + "rcpps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "V4SF")]) + +(define_insn "vmrcpv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (unspec:V4SF [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] + UNSPEC_RCP) + (match_operand:V4SF 2 "register_operand" "0") + (const_int 1)))] + "TARGET_SSE" + "rcpss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +(define_insn "rsqrtv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF + [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] UNSPEC_RSQRT))] + "TARGET_SSE" + "rsqrtps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "V4SF")]) + +(define_insn "vmrsqrtv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (unspec:V4SF [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] + UNSPEC_RSQRT) + (match_operand:V4SF 2 "register_operand" "0") + (const_int 1)))] + "TARGET_SSE" + "rsqrtss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +(define_insn "sqrtv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (sqrt:V4SF (match_operand:V4SF 1 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "sqrtps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "V4SF")]) + +(define_insn "vmsqrtv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (sqrt:V4SF (match_operand:V4SF 1 "nonimmediate_operand" "xm")) + (match_operand:V4SF 2 "register_operand" "0") + (const_int 1)))] + "TARGET_SSE" + "sqrtss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +;; SSE logical operations. + +;; SSE defines logical operations on floating point values. This brings +;; interesting challenge to RTL representation where logicals are only valid +;; on integral types. We deal with this by representing the floating point +;; logical as logical on arguments casted to TImode as this is what hardware +;; really does. Unfortunately hardware requires the type information to be +;; present and thus we must avoid subregs from being simplified and eliminated +;; in later compilation phases. +;; +;; We have following variants from each instruction: +;; sse_andsf3 - the operation taking V4SF vector operands +;; and doing TImode cast on them +;; *sse_andsf3_memory - the operation taking one memory operand casted to +;; TImode, since backend insist on eliminating casts +;; on memory operands +;; sse_andti3_sf_1 - the operation taking SF scalar operands. +;; We can not accept memory operand here as instruction reads +;; whole scalar. This is generated only post reload by GCC +;; scalar float operations that expands to logicals (fabs) +;; sse_andti3_sf_2 - the operation taking SF scalar input and TImode +;; memory operand. Eventually combine can be able +;; to synthesize these using splitter. +;; sse2_anddf3, *sse2_anddf3_memory +;; +;; +;; These are not called andti3 etc. because we really really don't want +;; the compiler to widen DImode ands to TImode ands and then try to move +;; into DImode subregs of SSE registers, and them together, and move out +;; of DImode subregs again! +;; SSE1 single precision floating point logical operation +(define_expand "sse_andv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "") + (and:V4SF (match_operand:V4SF 1 "register_operand" "") + (match_operand:V4SF 2 "nonimmediate_operand" "")))] + "TARGET_SSE" + "") + +(define_insn "*sse_andv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (and:V4SF (match_operand:V4SF 1 "nonimmediate_operand" "%0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "andps\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "V4SF")]) + +(define_expand "sse_nandv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "") + (and:V4SF (not:V4SF (match_operand:V4SF 1 "register_operand" "")) + (match_operand:V4SF 2 "nonimmediate_operand" "")))] + "TARGET_SSE" + "") + +(define_insn "*sse_nandv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (and:V4SF (not:V4SF (match_operand:V4SF 1 "register_operand" "0")) + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "andnps\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "V4SF")]) + +(define_expand "sse_iorv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "") + (ior:V4SF (match_operand:V4SF 1 "register_operand" "") + (match_operand:V4SF 2 "nonimmediate_operand" "")))] + "TARGET_SSE" + "") + +(define_insn "*sse_iorv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (ior:V4SF (match_operand:V4SF 1 "nonimmediate_operand" "%0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "orps\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "V4SF")]) + +(define_expand "sse_xorv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "") + (xor:V4SF (match_operand:V4SF 1 "register_operand" "") + (match_operand:V4SF 2 "nonimmediate_operand" "")))] + "TARGET_SSE" + "") + +(define_insn "*sse_xorv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (xor:V4SF (match_operand:V4SF 1 "nonimmediate_operand" "%0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "xorps\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "V4SF")]) + +;; SSE2 double precision floating point logical operation + +(define_expand "sse2_andv2df3" + [(set (match_operand:V2DF 0 "register_operand" "") + (and:V2DF (match_operand:V2DF 1 "register_operand" "") + (match_operand:V2DF 2 "nonimmediate_operand" "")))] + "TARGET_SSE2" + "") + +(define_insn "*sse2_andv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (and:V2DF (match_operand:V2DF 1 "nonimmediate_operand" "%0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2 + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "andpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "V2DF")]) + +(define_expand "sse2_nandv2df3" + [(set (match_operand:V2DF 0 "register_operand" "") + (and:V2DF (not:V2DF (match_operand:V2DF 1 "register_operand" "")) + (match_operand:V2DF 2 "nonimmediate_operand" "")))] + "TARGET_SSE2" + "") + +(define_insn "*sse2_nandv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (and:V2DF (not:V2DF (match_operand:V2DF 1 "register_operand" "0")) + (match_operand:V2DF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "andnpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "V2DF")]) + +(define_expand "sse2_iorv2df3" + [(set (match_operand:V2DF 0 "register_operand" "") + (ior:V2DF (match_operand:V2DF 1 "register_operand" "") + (match_operand:V2DF 2 "nonimmediate_operand" "")))] + "TARGET_SSE2" + "") + +(define_insn "*sse2_iorv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (ior:V2DF (match_operand:V2DF 1 "nonimmediate_operand" "%0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2 + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "orpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "V2DF")]) + +(define_expand "sse2_xorv2df3" + [(set (match_operand:V2DF 0 "register_operand" "") + (xor:V2DF (match_operand:V2DF 1 "nonimmediate_operand" "") + (match_operand:V2DF 2 "nonimmediate_operand" "")))] + "TARGET_SSE2" + "") + +(define_insn "*sse2_xorv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (xor:V2DF (match_operand:V2DF 1 "nonimmediate_operand" "%0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2 + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "xorpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "V2DF")]) + +;; SSE2 integral logicals. These patterns must always come after floating +;; point ones since we don't want compiler to use integer opcodes on floating +;; point SSE values to avoid matching of subregs in the match_operand. +(define_insn "*sse2_andti3" + [(set (match_operand:TI 0 "register_operand" "=x") + (and:TI (match_operand:TI 1 "nonimmediate_operand" "%0") + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2 + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "pand\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "TI")]) + +(define_insn "sse2_andv2di3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (and:V2DI (match_operand:V2DI 1 "nonimmediate_operand" "%0") + (match_operand:V2DI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2 + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "pand\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "TI")]) + +(define_insn "*sse2_nandti3" + [(set (match_operand:TI 0 "register_operand" "=x") + (and:TI (not:TI (match_operand:TI 1 "register_operand" "0")) + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pandn\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "TI")]) + +(define_insn "sse2_nandv2di3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (and:V2DI (not:V2DI (match_operand:V2DI 1 "register_operand" "0")) + (match_operand:V2DI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2 + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "pandn\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "TI")]) + +(define_insn "*sse2_iorti3" + [(set (match_operand:TI 0 "register_operand" "=x") + (ior:TI (match_operand:TI 1 "nonimmediate_operand" "%0") + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2 + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "por\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "TI")]) + +(define_insn "sse2_iorv2di3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (ior:V2DI (match_operand:V2DI 1 "nonimmediate_operand" "%0") + (match_operand:V2DI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2 + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "por\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "TI")]) + +(define_insn "*sse2_xorti3" + [(set (match_operand:TI 0 "register_operand" "=x") + (xor:TI (match_operand:TI 1 "nonimmediate_operand" "%0") + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2 + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "pxor\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "TI")]) + +(define_insn "sse2_xorv2di3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (xor:V2DI (match_operand:V2DI 1 "nonimmediate_operand" "%0") + (match_operand:V2DI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2 + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "pxor\t{%2, %0|%0, %2}" + [(set_attr "type" "sselog") + (set_attr "mode" "TI")]) + +;; Use xor, but don't show input operands so they aren't live before +;; this insn. +(define_insn "sse_clrv4sf" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (match_operand:V4SF 1 "const0_operand" "X"))] + "TARGET_SSE" +{ + if (get_attr_mode (insn) == MODE_TI) + return "pxor\t{%0, %0|%0, %0}"; + else + return "xorps\t{%0, %0|%0, %0}"; +} + [(set_attr "type" "sselog") + (set_attr "memory" "none") + (set (attr "mode") + (if_then_else + (and (and (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") + (const_int 0)) + (ne (symbol_ref "TARGET_SSE2") + (const_int 0))) + (eq (symbol_ref "optimize_size") + (const_int 0))) + (const_string "TI") + (const_string "V4SF")))]) + +;; Use xor, but don't show input operands so they aren't live before +;; this insn. +(define_insn "sse_clrv2df" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (unspec:V2DF [(const_int 0)] UNSPEC_NOP))] + "TARGET_SSE2" + "xorpd\t{%0, %0|%0, %0}" + [(set_attr "type" "sselog") + (set_attr "memory" "none") + (set_attr "mode" "V4SF")]) + +;; SSE mask-generating compares + +(define_insn "maskcmpv4sf3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (match_operator:V4SI 3 "sse_comparison_operator" + [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "register_operand" "x")]))] + "TARGET_SSE" + "cmp%D3ps\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecmp") + (set_attr "mode" "V4SF")]) + +(define_insn "maskncmpv4sf3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (not:V4SI + (match_operator:V4SI 3 "sse_comparison_operator" + [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "register_operand" "x")])))] + "TARGET_SSE" +{ + if (GET_CODE (operands[3]) == UNORDERED) + return "cmpordps\t{%2, %0|%0, %2}"; + else + return "cmpn%D3ps\t{%2, %0|%0, %2}"; +} + [(set_attr "type" "ssecmp") + (set_attr "mode" "V4SF")]) + +(define_insn "vmmaskcmpv4sf3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (vec_merge:V4SI + (match_operator:V4SI 3 "sse_comparison_operator" + [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "register_operand" "x")]) + (subreg:V4SI (match_dup 1) 0) + (const_int 1)))] + "TARGET_SSE" + "cmp%D3ss\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecmp") + (set_attr "mode" "SF")]) + +(define_insn "vmmaskncmpv4sf3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (vec_merge:V4SI + (not:V4SI + (match_operator:V4SI 3 "sse_comparison_operator" + [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "register_operand" "x")])) + (subreg:V4SI (match_dup 1) 0) + (const_int 1)))] + "TARGET_SSE" +{ + if (GET_CODE (operands[3]) == UNORDERED) + return "cmpordss\t{%2, %0|%0, %2}"; + else + return "cmpn%D3ss\t{%2, %0|%0, %2}"; +} + [(set_attr "type" "ssecmp") + (set_attr "mode" "SF")]) + +(define_insn "sse_comi" + [(set (reg:CCFP 17) + (compare:CCFP (vec_select:SF + (match_operand:V4SF 0 "register_operand" "x") + (parallel [(const_int 0)])) + (vec_select:SF + (match_operand:V4SF 1 "register_operand" "x") + (parallel [(const_int 0)]))))] + "TARGET_SSE" + "comiss\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecomi") + (set_attr "mode" "SF")]) + +(define_insn "sse_ucomi" + [(set (reg:CCFPU 17) + (compare:CCFPU (vec_select:SF + (match_operand:V4SF 0 "register_operand" "x") + (parallel [(const_int 0)])) + (vec_select:SF + (match_operand:V4SF 1 "register_operand" "x") + (parallel [(const_int 0)]))))] + "TARGET_SSE" + "ucomiss\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecomi") + (set_attr "mode" "SF")]) + + +;; SSE unpack + +(define_insn "sse_unpckhps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (vec_select:V4SF (match_operand:V4SF 1 "register_operand" "0") + (parallel [(const_int 2) + (const_int 0) + (const_int 3) + (const_int 1)])) + (vec_select:V4SF (match_operand:V4SF 2 "register_operand" "x") + (parallel [(const_int 0) + (const_int 2) + (const_int 1) + (const_int 3)])) + (const_int 5)))] + "TARGET_SSE" + "unpckhps\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + +(define_insn "sse_unpcklps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (vec_select:V4SF (match_operand:V4SF 1 "register_operand" "0") + (parallel [(const_int 0) + (const_int 2) + (const_int 1) + (const_int 3)])) + (vec_select:V4SF (match_operand:V4SF 2 "register_operand" "x") + (parallel [(const_int 2) + (const_int 0) + (const_int 3) + (const_int 1)])) + (const_int 5)))] + "TARGET_SSE" + "unpcklps\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + + +;; SSE min/max + +(define_insn "smaxv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (smax:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "maxps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "V4SF")]) + +(define_insn "vmsmaxv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (smax:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "maxss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +(define_insn "sminv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (smin:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "minps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "V4SF")]) + +(define_insn "vmsminv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (smin:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "minss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +;; SSE <-> integer/MMX conversions + +(define_insn "cvtpi2ps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0") + (vec_duplicate:V4SF + (float:V2SF (match_operand:V2SI 2 "nonimmediate_operand" "ym"))) + (const_int 12)))] + "TARGET_SSE" + "cvtpi2ps\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + +(define_insn "cvtps2pi" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (vec_select:V2SI + (fix:V4SI (match_operand:V4SF 1 "nonimmediate_operand" "xm")) + (parallel [(const_int 0) (const_int 1)])))] + "TARGET_SSE" + "cvtps2pi\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + +(define_insn "cvttps2pi" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (vec_select:V2SI + (unspec:V4SI [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] + UNSPEC_FIX) + (parallel [(const_int 0) (const_int 1)])))] + "TARGET_SSE" + "cvttps2pi\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "SF")]) + +(define_insn "cvtsi2ss" + [(set (match_operand:V4SF 0 "register_operand" "=x,x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0,0") + (vec_duplicate:V4SF + (float:SF (match_operand:SI 2 "nonimmediate_operand" "r,rm"))) + (const_int 14)))] + "TARGET_SSE" + "cvtsi2ss\t{%2, %0|%0, %2}" + [(set_attr "type" "sseicvt") + (set_attr "athlon_decode" "vector,double") + (set_attr "mode" "SF")]) + +(define_insn "cvtsi2ssq" + [(set (match_operand:V4SF 0 "register_operand" "=x,x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0,0") + (vec_duplicate:V4SF + (float:SF (match_operand:DI 2 "nonimmediate_operand" "r,rm"))) + (const_int 14)))] + "TARGET_SSE && TARGET_64BIT" + "cvtsi2ssq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseicvt") + (set_attr "athlon_decode" "vector,double") + (set_attr "mode" "SF")]) + +(define_insn "cvtss2si" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (vec_select:SI + (fix:V4SI (match_operand:V4SF 1 "nonimmediate_operand" "x,m")) + (parallel [(const_int 0)])))] + "TARGET_SSE" + "cvtss2si\t{%1, %0|%0, %1}" + [(set_attr "type" "sseicvt") + (set_attr "athlon_decode" "double,vector") + (set_attr "mode" "SI")]) + +(define_insn "cvtss2siq" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (vec_select:DI + (fix:V4DI (match_operand:V4SF 1 "nonimmediate_operand" "x,m")) + (parallel [(const_int 0)])))] + "TARGET_SSE" + "cvtss2siq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseicvt") + (set_attr "athlon_decode" "double,vector") + (set_attr "mode" "DI")]) + +(define_insn "cvttss2si" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (vec_select:SI + (unspec:V4SI [(match_operand:V4SF 1 "nonimmediate_operand" "x,xm")] + UNSPEC_FIX) + (parallel [(const_int 0)])))] + "TARGET_SSE" + "cvttss2si\t{%1, %0|%0, %1}" + [(set_attr "type" "sseicvt") + (set_attr "mode" "SF") + (set_attr "athlon_decode" "double,vector")]) + +(define_insn "cvttss2siq" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (vec_select:DI + (unspec:V4DI [(match_operand:V4SF 1 "nonimmediate_operand" "x,xm")] + UNSPEC_FIX) + (parallel [(const_int 0)])))] + "TARGET_SSE && TARGET_64BIT" + "cvttss2siq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseicvt") + (set_attr "mode" "SF") + (set_attr "athlon_decode" "double,vector")]) + + +;; MMX insns + +;; MMX arithmetic + +(define_insn "addv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (plus:V8QI (match_operand:V8QI 1 "register_operand" "%0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "addv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (plus:V4HI (match_operand:V4HI 1 "register_operand" "%0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "addv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (plus:V2SI (match_operand:V2SI 1 "register_operand" "%0") + (match_operand:V2SI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "mmx_adddi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(plus:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "nonimmediate_operand" "ym"))] + UNSPEC_NOP))] + "TARGET_MMX" + "paddq\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "ssaddv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (ss_plus:V8QI (match_operand:V8QI 1 "register_operand" "%0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddsb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "ssaddv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (ss_plus:V4HI (match_operand:V4HI 1 "register_operand" "%0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddsw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "usaddv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (us_plus:V8QI (match_operand:V8QI 1 "register_operand" "%0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddusb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "usaddv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (us_plus:V4HI (match_operand:V4HI 1 "register_operand" "%0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddusw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "subv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (minus:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "subv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (minus:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "subv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (minus:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:V2SI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "mmx_subdi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(minus:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonimmediate_operand" "ym"))] + UNSPEC_NOP))] + "TARGET_MMX" + "psubq\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "sssubv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (ss_minus:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubsb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "sssubv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (ss_minus:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubsw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "ussubv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (us_minus:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubusb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "ussubv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (us_minus:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubusw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "mulv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (mult:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pmullw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxmul") + (set_attr "mode" "DI")]) + +(define_insn "smulv4hi3_highpart" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (truncate:V4HI + (lshiftrt:V4SI + (mult:V4SI (sign_extend:V4SI + (match_operand:V4HI 1 "register_operand" "0")) + (sign_extend:V4SI + (match_operand:V4HI 2 "nonimmediate_operand" "ym"))) + (const_int 16))))] + "TARGET_MMX" + "pmulhw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxmul") + (set_attr "mode" "DI")]) + +(define_insn "umulv4hi3_highpart" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (truncate:V4HI + (lshiftrt:V4SI + (mult:V4SI (zero_extend:V4SI + (match_operand:V4HI 1 "register_operand" "0")) + (zero_extend:V4SI + (match_operand:V4HI 2 "nonimmediate_operand" "ym"))) + (const_int 16))))] + "TARGET_SSE || TARGET_3DNOW_A" + "pmulhuw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxmul") + (set_attr "mode" "DI")]) + +(define_insn "mmx_pmaddwd" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (plus:V2SI + (mult:V2SI + (sign_extend:V2SI + (vec_select:V2HI (match_operand:V4HI 1 "register_operand" "0") + (parallel [(const_int 0) (const_int 2)]))) + (sign_extend:V2SI + (vec_select:V2HI (match_operand:V4HI 2 "nonimmediate_operand" "ym") + (parallel [(const_int 0) (const_int 2)])))) + (mult:V2SI + (sign_extend:V2SI (vec_select:V2HI (match_dup 1) + (parallel [(const_int 1) + (const_int 3)]))) + (sign_extend:V2SI (vec_select:V2HI (match_dup 2) + (parallel [(const_int 1) + (const_int 3)]))))))] + "TARGET_MMX" + "pmaddwd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxmul") + (set_attr "mode" "DI")]) + + +;; MMX logical operations +;; Note we don't want to declare these as regular iordi3 insns to prevent +;; normal code that also wants to use the FPU from getting broken. +;; The UNSPECs are there to prevent the combiner from getting overly clever. +(define_insn "mmx_iordi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(ior:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "nonimmediate_operand" "ym"))] + UNSPEC_NOP))] + "TARGET_MMX" + "por\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "mmx_xordi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(xor:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "nonimmediate_operand" "ym"))] + UNSPEC_NOP))] + "TARGET_MMX" + "pxor\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI") + (set_attr "memory" "none")]) + +;; Same as pxor, but don't show input operands so that we don't think +;; they are live. +(define_insn "mmx_clrdi" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI [(const_int 0)] UNSPEC_NOP))] + "TARGET_MMX" + "pxor\t{%0, %0|%0, %0}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI") + (set_attr "memory" "none")]) + +(define_insn "mmx_anddi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(and:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "nonimmediate_operand" "ym"))] + UNSPEC_NOP))] + "TARGET_MMX" + "pand\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "mmx_nanddi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(and:DI (not:DI (match_operand:DI 1 "register_operand" "0")) + (match_operand:DI 2 "nonimmediate_operand" "ym"))] + UNSPEC_NOP))] + "TARGET_MMX" + "pandn\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + + +;; MMX unsigned averages/sum of absolute differences + +(define_insn "mmx_uavgv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (ashiftrt:V8QI + (plus:V8QI (plus:V8QI + (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")) + (const_vector:V8QI [(const_int 1) + (const_int 1) + (const_int 1) + (const_int 1) + (const_int 1) + (const_int 1) + (const_int 1) + (const_int 1)])) + (const_int 1)))] + "TARGET_SSE || TARGET_3DNOW_A" + "pavgb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +(define_insn "mmx_uavgv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (ashiftrt:V4HI + (plus:V4HI (plus:V4HI + (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")) + (const_vector:V4HI [(const_int 1) + (const_int 1) + (const_int 1) + (const_int 1)])) + (const_int 1)))] + "TARGET_SSE || TARGET_3DNOW_A" + "pavgw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +(define_insn "mmx_psadbw" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI [(match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")] + UNSPEC_PSADBW))] + "TARGET_SSE || TARGET_3DNOW_A" + "psadbw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + + +;; MMX insert/extract/shuffle + +(define_insn "mmx_pinsrw" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (vec_merge:V4HI (match_operand:V4HI 1 "register_operand" "0") + (vec_duplicate:V4HI + (truncate:HI (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (match_operand:SI 3 "const_0_to_15_operand" "N")))] + "TARGET_SSE || TARGET_3DNOW_A" + "pinsrw\t{%3, %2, %0|%0, %2, %3}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + +(define_insn "mmx_pextrw" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (vec_select:HI (match_operand:V4HI 1 "register_operand" "y") + (parallel + [(match_operand:SI 2 "const_0_to_3_operand" "N")]))))] + "TARGET_SSE || TARGET_3DNOW_A" + "pextrw\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + +(define_insn "mmx_pshufw" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (unspec:V4HI [(match_operand:V4HI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")] + UNSPEC_SHUFFLE))] + "TARGET_SSE || TARGET_3DNOW_A" + "pshufw\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + + +;; MMX mask-generating comparisons + +(define_insn "eqv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (eq:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpeqb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcmp") + (set_attr "mode" "DI")]) + +(define_insn "eqv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (eq:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpeqw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcmp") + (set_attr "mode" "DI")]) + +(define_insn "eqv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (eq:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:V2SI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpeqd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcmp") + (set_attr "mode" "DI")]) + +(define_insn "gtv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (gt:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpgtb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcmp") + (set_attr "mode" "DI")]) + +(define_insn "gtv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (gt:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpgtw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcmp") + (set_attr "mode" "DI")]) + +(define_insn "gtv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (gt:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:V2SI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpgtd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcmp") + (set_attr "mode" "DI")]) + + +;; MMX max/min insns + +(define_insn "umaxv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (umax:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_SSE || TARGET_3DNOW_A" + "pmaxub\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "smaxv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (smax:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_SSE || TARGET_3DNOW_A" + "pmaxsw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "uminv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (umin:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_SSE || TARGET_3DNOW_A" + "pminub\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + +(define_insn "sminv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (smin:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_SSE || TARGET_3DNOW_A" + "pminsw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "DI")]) + + +;; MMX shifts + +(define_insn "ashrv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (ashiftrt:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "psraw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +(define_insn "ashrv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (ashiftrt:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "psrad\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +(define_insn "lshrv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (lshiftrt:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "psrlw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +(define_insn "lshrv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (lshiftrt:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "psrld\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +;; See logical MMX insns. +(define_insn "mmx_lshrdi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(lshiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi"))] + UNSPEC_NOP))] + "TARGET_MMX" + "psrlq\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +(define_insn "ashlv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (ashift:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "psllw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +(define_insn "ashlv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (ashift:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "pslld\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +;; See logical MMX insns. +(define_insn "mmx_ashldi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(ashift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi"))] + UNSPEC_NOP))] + "TARGET_MMX" + "psllq\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + + +;; MMX pack/unpack insns. + +(define_insn "mmx_packsswb" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (vec_concat:V8QI + (ss_truncate:V4QI (match_operand:V4HI 1 "register_operand" "0")) + (ss_truncate:V4QI (match_operand:V4HI 2 "register_operand" "y"))))] + "TARGET_MMX" + "packsswb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +(define_insn "mmx_packssdw" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (vec_concat:V4HI + (ss_truncate:V2HI (match_operand:V2SI 1 "register_operand" "0")) + (ss_truncate:V2HI (match_operand:V2SI 2 "register_operand" "y"))))] + "TARGET_MMX" + "packssdw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +(define_insn "mmx_packuswb" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (vec_concat:V8QI + (us_truncate:V4QI (match_operand:V4HI 1 "register_operand" "0")) + (us_truncate:V4QI (match_operand:V4HI 2 "register_operand" "y"))))] + "TARGET_MMX" + "packuswb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "DI")]) + +(define_insn "mmx_punpckhbw" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (vec_merge:V8QI + (vec_select:V8QI (match_operand:V8QI 1 "register_operand" "0") + (parallel [(const_int 4) + (const_int 0) + (const_int 5) + (const_int 1) + (const_int 6) + (const_int 2) + (const_int 7) + (const_int 3)])) + (vec_select:V8QI (match_operand:V8QI 2 "register_operand" "y") + (parallel [(const_int 0) + (const_int 4) + (const_int 1) + (const_int 5) + (const_int 2) + (const_int 6) + (const_int 3) + (const_int 7)])) + (const_int 85)))] + "TARGET_MMX" + "punpckhbw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + +(define_insn "mmx_punpckhwd" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (vec_merge:V4HI + (vec_select:V4HI (match_operand:V4HI 1 "register_operand" "0") + (parallel [(const_int 0) + (const_int 2) + (const_int 1) + (const_int 3)])) + (vec_select:V4HI (match_operand:V4HI 2 "register_operand" "y") + (parallel [(const_int 2) + (const_int 0) + (const_int 3) + (const_int 1)])) + (const_int 5)))] + "TARGET_MMX" + "punpckhwd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + +(define_insn "mmx_punpckhdq" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (vec_merge:V2SI + (match_operand:V2SI 1 "register_operand" "0") + (vec_select:V2SI (match_operand:V2SI 2 "register_operand" "y") + (parallel [(const_int 1) + (const_int 0)])) + (const_int 1)))] + "TARGET_MMX" + "punpckhdq\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + +(define_insn "mmx_punpcklbw" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (vec_merge:V8QI + (vec_select:V8QI (match_operand:V8QI 1 "register_operand" "0") + (parallel [(const_int 0) + (const_int 4) + (const_int 1) + (const_int 5) + (const_int 2) + (const_int 6) + (const_int 3) + (const_int 7)])) + (vec_select:V8QI (match_operand:V8QI 2 "register_operand" "y") + (parallel [(const_int 4) + (const_int 0) + (const_int 5) + (const_int 1) + (const_int 6) + (const_int 2) + (const_int 7) + (const_int 3)])) + (const_int 85)))] + "TARGET_MMX" + "punpcklbw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + +(define_insn "mmx_punpcklwd" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (vec_merge:V4HI + (vec_select:V4HI (match_operand:V4HI 1 "register_operand" "0") + (parallel [(const_int 2) + (const_int 0) + (const_int 3) + (const_int 1)])) + (vec_select:V4HI (match_operand:V4HI 2 "register_operand" "y") + (parallel [(const_int 0) + (const_int 2) + (const_int 1) + (const_int 3)])) + (const_int 5)))] + "TARGET_MMX" + "punpcklwd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + +(define_insn "mmx_punpckldq" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (vec_merge:V2SI + (vec_select:V2SI (match_operand:V2SI 1 "register_operand" "0") + (parallel [(const_int 1) + (const_int 0)])) + (match_operand:V2SI 2 "register_operand" "y") + (const_int 1)))] + "TARGET_MMX" + "punpckldq\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "DI")]) + + +;; Miscellaneous stuff + +(define_insn "emms" + [(unspec_volatile [(const_int 0)] UNSPECV_EMMS) + (clobber (reg:XF 8)) + (clobber (reg:XF 9)) + (clobber (reg:XF 10)) + (clobber (reg:XF 11)) + (clobber (reg:XF 12)) + (clobber (reg:XF 13)) + (clobber (reg:XF 14)) + (clobber (reg:XF 15)) + (clobber (reg:DI 29)) + (clobber (reg:DI 30)) + (clobber (reg:DI 31)) + (clobber (reg:DI 32)) + (clobber (reg:DI 33)) + (clobber (reg:DI 34)) + (clobber (reg:DI 35)) + (clobber (reg:DI 36))] + "TARGET_MMX" + "emms" + [(set_attr "type" "mmx") + (set_attr "memory" "unknown")]) + +(define_insn "ldmxcsr" + [(unspec_volatile [(match_operand:SI 0 "memory_operand" "m")] + UNSPECV_LDMXCSR)] + "TARGET_SSE" + "ldmxcsr\t%0" + [(set_attr "type" "sse") + (set_attr "memory" "load")]) + +(define_insn "stmxcsr" + [(set (match_operand:SI 0 "memory_operand" "=m") + (unspec_volatile:SI [(const_int 0)] UNSPECV_STMXCSR))] + "TARGET_SSE" + "stmxcsr\t%0" + [(set_attr "type" "sse") + (set_attr "memory" "store")]) + +(define_expand "sfence" + [(set (match_dup 0) + (unspec:BLK [(match_dup 0)] UNSPEC_SFENCE))] + "TARGET_SSE || TARGET_3DNOW_A" +{ + operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); + MEM_VOLATILE_P (operands[0]) = 1; +}) + +(define_insn "*sfence_insn" + [(set (match_operand:BLK 0 "" "") + (unspec:BLK [(match_dup 0)] UNSPEC_SFENCE))] + "TARGET_SSE || TARGET_3DNOW_A" + "sfence" + [(set_attr "type" "sse") + (set_attr "memory" "unknown")]) (define_expand "sse_prologue_save" [(parallel [(set (match_operand:BLK 0 "" "") @@ -20718,6 +20919,311 @@ (set_attr "modrm" "0") (set_attr "mode" "DI")]) +;; 3Dnow! instructions + +(define_insn "addv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (plus:V2SF (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfadd\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "V2SF")]) + +(define_insn "subv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (minus:V2SF (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfsub\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "V2SF")]) + +(define_insn "subrv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (minus:V2SF (match_operand:V2SF 2 "nonimmediate_operand" "ym") + (match_operand:V2SF 1 "register_operand" "0")))] + "TARGET_3DNOW" + "pfsubr\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "V2SF")]) + +(define_insn "gtv2sf3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (gt:V2SI (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfcmpgt\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcmp") + (set_attr "mode" "V2SF")]) + +(define_insn "gev2sf3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (ge:V2SI (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfcmpge\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcmp") + (set_attr "mode" "V2SF")]) + +(define_insn "eqv2sf3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (eq:V2SI (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfcmpeq\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxcmp") + (set_attr "mode" "V2SF")]) + +(define_insn "pfmaxv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (smax:V2SF (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfmax\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "V2SF")]) + +(define_insn "pfminv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (smin:V2SF (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfmin\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "V2SF")]) + +(define_insn "mulv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (mult:V2SF (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfmul\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxmul") + (set_attr "mode" "V2SF")]) + +(define_insn "femms" + [(unspec_volatile [(const_int 0)] UNSPECV_FEMMS) + (clobber (reg:XF 8)) + (clobber (reg:XF 9)) + (clobber (reg:XF 10)) + (clobber (reg:XF 11)) + (clobber (reg:XF 12)) + (clobber (reg:XF 13)) + (clobber (reg:XF 14)) + (clobber (reg:XF 15)) + (clobber (reg:DI 29)) + (clobber (reg:DI 30)) + (clobber (reg:DI 31)) + (clobber (reg:DI 32)) + (clobber (reg:DI 33)) + (clobber (reg:DI 34)) + (clobber (reg:DI 35)) + (clobber (reg:DI 36))] + "TARGET_3DNOW" + "femms" + [(set_attr "type" "mmx") + (set_attr "memory" "none")]) + +(define_insn "pf2id" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (fix:V2SI (match_operand:V2SF 1 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pf2id\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "V2SF")]) + +(define_insn "pf2iw" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (sign_extend:V2SI + (ss_truncate:V2HI + (fix:V2SI (match_operand:V2SF 1 "nonimmediate_operand" "ym")))))] + "TARGET_3DNOW_A" + "pf2iw\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "V2SF")]) + +(define_insn "pfacc" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (vec_concat:V2SF + (plus:SF + (vec_select:SF (match_operand:V2SF 1 "register_operand" "0") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 1) + (parallel [(const_int 1)]))) + (plus:SF + (vec_select:SF (match_operand:V2SF 2 "nonimmediate_operand" "y") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 2) + (parallel [(const_int 1)])))))] + "TARGET_3DNOW" + "pfacc\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "V2SF")]) + +(define_insn "pfnacc" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (vec_concat:V2SF + (minus:SF + (vec_select:SF (match_operand:V2SF 1 "register_operand" "0") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 1) + (parallel [(const_int 1)]))) + (minus:SF + (vec_select:SF (match_operand:V2SF 2 "nonimmediate_operand" "y") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 2) + (parallel [(const_int 1)])))))] + "TARGET_3DNOW_A" + "pfnacc\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "V2SF")]) + +(define_insn "pfpnacc" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (vec_concat:V2SF + (minus:SF + (vec_select:SF (match_operand:V2SF 1 "register_operand" "0") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 1) + (parallel [(const_int 1)]))) + (plus:SF + (vec_select:SF (match_operand:V2SF 2 "nonimmediate_operand" "y") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 2) + (parallel [(const_int 1)])))))] + "TARGET_3DNOW_A" + "pfpnacc\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxadd") + (set_attr "mode" "V2SF")]) + +(define_insn "pi2fw" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (float:V2SF + (vec_concat:V2SI + (sign_extend:SI + (truncate:HI + (vec_select:SI (match_operand:V2SI 1 "nonimmediate_operand" "ym") + (parallel [(const_int 0)])))) + (sign_extend:SI + (truncate:HI + (vec_select:SI (match_dup 1) + (parallel [(const_int 1)])))))))] + "TARGET_3DNOW_A" + "pi2fw\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "V2SF")]) + +(define_insn "floatv2si2" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (float:V2SF (match_operand:V2SI 1 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pi2fd\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "V2SF")]) + +;; This insn is identical to pavgb in operation, but the opcode is +;; different. To avoid accidentally matching pavgb, use an unspec. + +(define_insn "pavgusb" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (unspec:V8QI + [(match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")] + UNSPEC_PAVGUSB))] + "TARGET_3DNOW" + "pavgusb\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxshft") + (set_attr "mode" "TI")]) + +;; 3DNow reciprocal and sqrt + +(define_insn "pfrcpv2sf2" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (unspec:V2SF [(match_operand:V2SF 1 "nonimmediate_operand" "ym")] + UNSPEC_PFRCP))] + "TARGET_3DNOW" + "pfrcp\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx") + (set_attr "mode" "TI")]) + +(define_insn "pfrcpit1v2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (unspec:V2SF [(match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")] + UNSPEC_PFRCPIT1))] + "TARGET_3DNOW" + "pfrcpit1\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx") + (set_attr "mode" "TI")]) + +(define_insn "pfrcpit2v2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (unspec:V2SF [(match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")] + UNSPEC_PFRCPIT2))] + "TARGET_3DNOW" + "pfrcpit2\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx") + (set_attr "mode" "TI")]) + +(define_insn "pfrsqrtv2sf2" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (unspec:V2SF [(match_operand:V2SF 1 "nonimmediate_operand" "ym")] + UNSPEC_PFRSQRT))] + "TARGET_3DNOW" + "pfrsqrt\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx") + (set_attr "mode" "TI")]) + +(define_insn "pfrsqit1v2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (unspec:V2SF [(match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")] + UNSPEC_PFRSQIT1))] + "TARGET_3DNOW" + "pfrsqit1\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx") + (set_attr "mode" "TI")]) + +(define_insn "pmulhrwv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (truncate:V4HI + (lshiftrt:V4SI + (plus:V4SI + (mult:V4SI + (sign_extend:V4SI + (match_operand:V4HI 1 "register_operand" "0")) + (sign_extend:V4SI + (match_operand:V4HI 2 "nonimmediate_operand" "ym"))) + (const_vector:V4SI [(const_int 32768) + (const_int 32768) + (const_int 32768) + (const_int 32768)])) + (const_int 16))))] + "TARGET_3DNOW" + "pmulhrw\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmxmul") + (set_attr "mode" "TI")]) + +(define_insn "pswapdv2si2" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (vec_select:V2SI (match_operand:V2SI 1 "nonimmediate_operand" "ym") + (parallel [(const_int 1) (const_int 0)])))] + "TARGET_3DNOW_A" + "pswapd\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "TI")]) + +(define_insn "pswapdv2sf2" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (vec_select:V2SF (match_operand:V2SF 1 "nonimmediate_operand" "ym") + (parallel [(const_int 1) (const_int 0)])))] + "TARGET_3DNOW_A" + "pswapd\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmxcvt") + (set_attr "mode" "TI")]) + (define_expand "prefetch" [(prefetch (match_operand 0 "address_operand" "") (match_operand:SI 1 "const_int_operand" "") @@ -20727,13 +21233,15 @@ int rw = INTVAL (operands[1]); int locality = INTVAL (operands[2]); - gcc_assert (rw == 0 || rw == 1); - gcc_assert (locality >= 0 && locality <= 3); - gcc_assert (GET_MODE (operands[0]) == Pmode - || GET_MODE (operands[0]) == VOIDmode); + if (rw != 0 && rw != 1) + abort (); + if (locality < 0 || locality > 3) + abort (); + if (GET_MODE (operands[0]) != Pmode && GET_MODE (operands[0]) != VOIDmode) + abort (); /* Use 3dNOW prefetch in case we are asking for write prefetch not - supported by SSE counterpart or the SSE prefetch is not available + suported by SSE counterpart or the SSE prefetch is not available (K6 machines). Otherwise use SSE prefetch as it allows specifying of locality. */ if (TARGET_3DNOW && (!TARGET_PREFETCH_SSE || rw)) @@ -20753,7 +21261,8 @@ }; int locality = INTVAL (operands[1]); - gcc_assert (locality >= 0 && locality <= 3); + if (locality < 0 || locality > 3) + abort (); return patterns[locality]; } @@ -20771,7 +21280,8 @@ }; int locality = INTVAL (operands[1]); - gcc_assert (locality >= 0 && locality <= 3); + if (locality < 0 || locality > 3) + abort (); return patterns[locality]; } @@ -20806,147 +21316,1706 @@ [(set_attr "type" "mmx") (set_attr "memory" "none")]) -(define_expand "stack_protect_set" - [(match_operand 0 "memory_operand" "") - (match_operand 1 "memory_operand" "")] - "" +;; SSE2 support + +(define_insn "addv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (plus:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "addpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V2DF")]) + +(define_insn "vmaddv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_merge:V2DF (plus:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE2" + "addsd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "DF")]) + +(define_insn "subv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (minus:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "subpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V2DF")]) + +(define_insn "vmsubv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_merge:V2DF (minus:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE2" + "subsd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "DF")]) + +(define_insn "mulv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (mult:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "mulpd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssemul") + (set_attr "mode" "V2DF")]) + +(define_insn "vmmulv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_merge:V2DF (mult:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE2" + "mulsd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssemul") + (set_attr "mode" "DF")]) + +(define_insn "divv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (div:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "divpd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssediv") + (set_attr "mode" "V2DF")]) + +(define_insn "vmdivv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_merge:V2DF (div:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE2" + "divsd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssediv") + (set_attr "mode" "DF")]) + +;; SSE min/max + +(define_insn "smaxv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (smax:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "maxpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V2DF")]) + +(define_insn "vmsmaxv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_merge:V2DF (smax:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE2" + "maxsd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "DF")]) + +(define_insn "sminv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (smin:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "minpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V2DF")]) + +(define_insn "vmsminv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_merge:V2DF (smin:V2DF (match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE2" + "minsd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "DF")]) +;; SSE2 square root. There doesn't appear to be an extension for the +;; reciprocal/rsqrt instructions if the Intel manual is to be believed. + +(define_insn "sqrtv2df2" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (sqrt:V2DF (match_operand:V2DF 1 "register_operand" "xm")))] + "TARGET_SSE2" + "sqrtpd\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "V2DF")]) + +(define_insn "vmsqrtv2df2" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_merge:V2DF (sqrt:V2DF (match_operand:V2DF 1 "register_operand" "xm")) + (match_operand:V2DF 2 "register_operand" "0") + (const_int 1)))] + "TARGET_SSE2" + "sqrtsd\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +;; SSE mask-generating compares + +(define_insn "maskcmpv2df3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (match_operator:V2DI 3 "sse_comparison_operator" + [(match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "x")]))] + "TARGET_SSE2" + "cmp%D3pd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecmp") + (set_attr "mode" "V2DF")]) + +(define_insn "maskncmpv2df3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (not:V2DI + (match_operator:V2DI 3 "sse_comparison_operator" + [(match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "x")])))] + "TARGET_SSE2" { -#ifdef TARGET_THREAD_SSP_OFFSET - if (TARGET_64BIT) - emit_insn (gen_stack_tls_protect_set_di (operands[0], - GEN_INT (TARGET_THREAD_SSP_OFFSET))); + if (GET_CODE (operands[3]) == UNORDERED) + return "cmpordps\t{%2, %0|%0, %2}"; else - emit_insn (gen_stack_tls_protect_set_si (operands[0], - GEN_INT (TARGET_THREAD_SSP_OFFSET))); -#else - if (TARGET_64BIT) - emit_insn (gen_stack_protect_set_di (operands[0], operands[1])); + return "cmpn%D3pd\t{%2, %0|%0, %2}"; +} + [(set_attr "type" "ssecmp") + (set_attr "mode" "V2DF")]) + +(define_insn "vmmaskcmpv2df3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (vec_merge:V2DI + (match_operator:V2DI 3 "sse_comparison_operator" + [(match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "x")]) + (subreg:V2DI (match_dup 1) 0) + (const_int 1)))] + "TARGET_SSE2" + "cmp%D3sd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecmp") + (set_attr "mode" "DF")]) + +(define_insn "vmmaskncmpv2df3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (vec_merge:V2DI + (not:V2DI + (match_operator:V2DI 3 "sse_comparison_operator" + [(match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "x")])) + (subreg:V2DI (match_dup 1) 0) + (const_int 1)))] + "TARGET_SSE2" +{ + if (GET_CODE (operands[3]) == UNORDERED) + return "cmpordsd\t{%2, %0|%0, %2}"; else - emit_insn (gen_stack_protect_set_si (operands[0], operands[1])); -#endif - DONE; -}) + return "cmpn%D3sd\t{%2, %0|%0, %2}"; +} + [(set_attr "type" "ssecmp") + (set_attr "mode" "DF")]) -(define_insn "stack_protect_set_si" - [(set (match_operand:SI 0 "memory_operand" "=m") - (unspec:SI [(match_operand:SI 1 "memory_operand" "m")] UNSPEC_SP_SET)) - (set (match_scratch:SI 2 "=&r") (const_int 0)) - (clobber (reg:CC FLAGS_REG))] - "" - "mov{l}\t{%1, %2|%2, %1}\;mov{l}\t{%2, %0|%0, %2}\;xor{l}\t%2, %2" - [(set_attr "type" "multi")]) +(define_insn "sse2_comi" + [(set (reg:CCFP 17) + (compare:CCFP (vec_select:DF + (match_operand:V2DF 0 "register_operand" "x") + (parallel [(const_int 0)])) + (vec_select:DF + (match_operand:V2DF 1 "register_operand" "x") + (parallel [(const_int 0)]))))] + "TARGET_SSE2" + "comisd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecomi") + (set_attr "mode" "DF")]) -(define_insn "stack_protect_set_di" - [(set (match_operand:DI 0 "memory_operand" "=m") - (unspec:DI [(match_operand:DI 1 "memory_operand" "m")] UNSPEC_SP_SET)) - (set (match_scratch:DI 2 "=&r") (const_int 0)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "mov{q}\t{%1, %2|%2, %1}\;mov{q}\t{%2, %0|%0, %2}\;xor{l}\t%k2, %k2" - [(set_attr "type" "multi")]) +(define_insn "sse2_ucomi" + [(set (reg:CCFPU 17) + (compare:CCFPU (vec_select:DF + (match_operand:V2DF 0 "register_operand" "x") + (parallel [(const_int 0)])) + (vec_select:DF + (match_operand:V2DF 1 "register_operand" "x") + (parallel [(const_int 0)]))))] + "TARGET_SSE2" + "ucomisd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecomi") + (set_attr "mode" "DF")]) + +;; SSE Strange Moves. -(define_insn "stack_tls_protect_set_si" +(define_insn "sse2_movmskpd" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:V2DF 1 "register_operand" "x")] + UNSPEC_MOVMSK))] + "TARGET_SSE2" + "movmskpd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +(define_insn "sse2_pmovmskb" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:V16QI 1 "register_operand" "x")] + UNSPEC_MOVMSK))] + "TARGET_SSE2" + "pmovmskb\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +(define_insn "sse2_maskmovdqu" + [(set (mem:V16QI (match_operand:SI 0 "register_operand" "D")) + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "x") + (match_operand:V16QI 2 "register_operand" "x")] + UNSPEC_MASKMOV))] + "TARGET_SSE2" + ;; @@@ check ordering of operands in intel/nonintel syntax + "maskmovdqu\t{%2, %1|%1, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_maskmovdqu_rex64" + [(set (mem:V16QI (match_operand:DI 0 "register_operand" "D")) + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "x") + (match_operand:V16QI 2 "register_operand" "x")] + UNSPEC_MASKMOV))] + "TARGET_SSE2" + ;; @@@ check ordering of operands in intel/nonintel syntax + "maskmovdqu\t{%2, %1|%1, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_movntv2df" + [(set (match_operand:V2DF 0 "memory_operand" "=m") + (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "x")] + UNSPEC_MOVNT))] + "TARGET_SSE2" + "movntpd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +(define_insn "sse2_movntv2di" + [(set (match_operand:V2DI 0 "memory_operand" "=m") + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "x")] + UNSPEC_MOVNT))] + "TARGET_SSE2" + "movntdq\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_movntsi" [(set (match_operand:SI 0 "memory_operand" "=m") - (unspec:SI [(match_operand:SI 1 "const_int_operand" "i")] UNSPEC_SP_TLS_SET)) - (set (match_scratch:SI 2 "=&r") (const_int 0)) - (clobber (reg:CC FLAGS_REG))] - "" - "mov{l}\t{%%gs:%P1, %2|%2, DWORD PTR %%gs:%P1}\;mov{l}\t{%2, %0|%0, %2}\;xor{l}\t%2, %2" - [(set_attr "type" "multi")]) + (unspec:SI [(match_operand:SI 1 "register_operand" "r")] + UNSPEC_MOVNT))] + "TARGET_SSE2" + "movnti\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) -(define_insn "stack_tls_protect_set_di" - [(set (match_operand:DI 0 "memory_operand" "=m") - (unspec:DI [(match_operand:DI 1 "const_int_operand" "i")] UNSPEC_SP_TLS_SET)) - (set (match_scratch:DI 2 "=&r") (const_int 0)) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - { - /* The kernel uses a different segment register for performance reasons; a - system call would not have to trash the userspace segment register, - which would be expensive */ - if (ix86_cmodel != CM_KERNEL) - return "mov{q}\t{%%fs:%P1, %2|%2, QWORD PTR %%fs:%P1}\;mov{q}\t{%2, %0|%0, %2}\;xor{l}\t%k2, %k2"; - else - return "mov{q}\t{%%gs:%P1, %2|%2, QWORD PTR %%gs:%P1}\;mov{q}\t{%2, %0|%0, %2}\;xor{l}\t%k2, %k2"; - } - [(set_attr "type" "multi")]) +;; SSE <-> integer/MMX conversions -(define_expand "stack_protect_test" - [(match_operand 0 "memory_operand" "") - (match_operand 1 "memory_operand" "") - (match_operand 2 "" "")] - "" -{ - rtx flags = gen_rtx_REG (CCZmode, FLAGS_REG); - ix86_compare_op0 = operands[0]; - ix86_compare_op1 = operands[1]; - ix86_compare_emitted = flags; +;; Conversions between SI and SF -#ifdef TARGET_THREAD_SSP_OFFSET - if (TARGET_64BIT) - emit_insn (gen_stack_tls_protect_test_di (flags, operands[0], - GEN_INT (TARGET_THREAD_SSP_OFFSET))); - else - emit_insn (gen_stack_tls_protect_test_si (flags, operands[0], - GEN_INT (TARGET_THREAD_SSP_OFFSET))); -#else - if (TARGET_64BIT) - emit_insn (gen_stack_protect_test_di (flags, operands[0], operands[1])); +(define_insn "cvtdq2ps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (float:V4SF (match_operand:V4SI 1 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "cvtdq2ps\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +(define_insn "cvtps2dq" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (fix:V4SI (match_operand:V4SF 1 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "cvtps2dq\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "cvttps2dq" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (unspec:V4SI [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] + UNSPEC_FIX))] + "TARGET_SSE2" + "cvttps2dq\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +;; Conversions between SI and DF + +(define_insn "cvtdq2pd" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (float:V2DF (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "xm") + (parallel + [(const_int 0) + (const_int 1)]))))] + "TARGET_SSE2" + "cvtdq2pd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +(define_insn "cvtpd2dq" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (vec_concat:V4SI + (fix:V2SI (match_operand:V2DF 1 "nonimmediate_operand" "xm")) + (const_vector:V2SI [(const_int 0) (const_int 0)])))] + "TARGET_SSE2" + "cvtpd2dq\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "cvttpd2dq" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (vec_concat:V4SI + (unspec:V2SI [(match_operand:V2DF 1 "nonimmediate_operand" "xm")] + UNSPEC_FIX) + (const_vector:V2SI [(const_int 0) (const_int 0)])))] + "TARGET_SSE2" + "cvttpd2dq\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "cvtpd2pi" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (fix:V2SI (match_operand:V2DF 1 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "cvtpd2pi\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "cvttpd2pi" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (unspec:V2SI [(match_operand:V2DF 1 "nonimmediate_operand" "xm")] + UNSPEC_FIX))] + "TARGET_SSE2" + "cvttpd2pi\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "cvtpi2pd" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (float:V2DF (match_operand:V2SI 1 "nonimmediate_operand" "ym")))] + "TARGET_SSE2" + "cvtpi2pd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +;; Conversions between SI and DF + +(define_insn "cvtsd2si" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (fix:SI (vec_select:DF (match_operand:V2DF 1 "register_operand" "x,m") + (parallel [(const_int 0)]))))] + "TARGET_SSE2" + "cvtsd2si\t{%1, %0|%0, %1}" + [(set_attr "type" "sseicvt") + (set_attr "athlon_decode" "double,vector") + (set_attr "mode" "SI")]) + +(define_insn "cvtsd2siq" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (fix:DI (vec_select:DF (match_operand:V2DF 1 "register_operand" "x,m") + (parallel [(const_int 0)]))))] + "TARGET_SSE2 && TARGET_64BIT" + "cvtsd2siq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseicvt") + (set_attr "athlon_decode" "double,vector") + (set_attr "mode" "DI")]) + +(define_insn "cvttsd2si" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (unspec:SI [(vec_select:DF (match_operand:V2DF 1 "register_operand" "x,xm") + (parallel [(const_int 0)]))] UNSPEC_FIX))] + "TARGET_SSE2" + "cvttsd2si\t{%1, %0|%0, %1}" + [(set_attr "type" "sseicvt") + (set_attr "mode" "SI") + (set_attr "athlon_decode" "double,vector")]) + +(define_insn "cvttsd2siq" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (unspec:DI [(vec_select:DF (match_operand:V2DF 1 "register_operand" "x,xm") + (parallel [(const_int 0)]))] UNSPEC_FIX))] + "TARGET_SSE2 && TARGET_64BIT" + "cvttsd2siq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseicvt") + (set_attr "mode" "DI") + (set_attr "athlon_decode" "double,vector")]) + +(define_insn "cvtsi2sd" + [(set (match_operand:V2DF 0 "register_operand" "=x,x") + (vec_merge:V2DF (match_operand:V2DF 1 "register_operand" "0,0") + (vec_duplicate:V2DF + (float:DF + (match_operand:SI 2 "nonimmediate_operand" "r,rm"))) + (const_int 2)))] + "TARGET_SSE2" + "cvtsi2sd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseicvt") + (set_attr "mode" "DF") + (set_attr "athlon_decode" "double,direct")]) + +(define_insn "cvtsi2sdq" + [(set (match_operand:V2DF 0 "register_operand" "=x,x") + (vec_merge:V2DF (match_operand:V2DF 1 "register_operand" "0,0") + (vec_duplicate:V2DF + (float:DF + (match_operand:DI 2 "nonimmediate_operand" "r,rm"))) + (const_int 2)))] + "TARGET_SSE2 && TARGET_64BIT" + "cvtsi2sdq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseicvt") + (set_attr "mode" "DF") + (set_attr "athlon_decode" "double,direct")]) + +;; Conversions between SF and DF + +(define_insn "cvtsd2ss" + [(set (match_operand:V4SF 0 "register_operand" "=x,x") + (vec_merge:V4SF (match_operand:V4SF 1 "register_operand" "0,0") + (vec_duplicate:V4SF + (float_truncate:V2SF + (match_operand:V2DF 2 "nonimmediate_operand" "x,xm"))) + (const_int 14)))] + "TARGET_SSE2" + "cvtsd2ss\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "athlon_decode" "vector,double") + (set_attr "mode" "SF")]) + +(define_insn "cvtss2sd" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_merge:V2DF (match_operand:V2DF 1 "register_operand" "0") + (float_extend:V2DF + (vec_select:V2SF + (match_operand:V4SF 2 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 1)]))) + (const_int 2)))] + "TARGET_SSE2" + "cvtss2sd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "DF")]) + +(define_insn "cvtpd2ps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (subreg:V4SF + (vec_concat:V4SI + (subreg:V2SI (float_truncate:V2SF + (match_operand:V2DF 1 "nonimmediate_operand" "xm")) 0) + (const_vector:V2SI [(const_int 0) (const_int 0)])) 0))] + "TARGET_SSE2" + "cvtpd2ps\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V4SF")]) + +(define_insn "cvtps2pd" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (float_extend:V2DF + (vec_select:V2SF (match_operand:V4SF 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 1)]))))] + "TARGET_SSE2" + "cvtps2pd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +;; SSE2 variants of MMX insns + +;; MMX arithmetic + +(define_insn "addv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (plus:V16QI (match_operand:V16QI 1 "register_operand" "%0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "paddb\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "addv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (plus:V8HI (match_operand:V8HI 1 "register_operand" "%0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "paddw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "addv4si3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (plus:V4SI (match_operand:V4SI 1 "register_operand" "%0") + (match_operand:V4SI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "paddd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "addv2di3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (plus:V2DI (match_operand:V2DI 1 "register_operand" "%0") + (match_operand:V2DI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "paddq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "ssaddv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (ss_plus:V16QI (match_operand:V16QI 1 "register_operand" "%0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "paddsb\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "ssaddv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (ss_plus:V8HI (match_operand:V8HI 1 "register_operand" "%0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "paddsw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "usaddv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (us_plus:V16QI (match_operand:V16QI 1 "register_operand" "%0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "paddusb\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "usaddv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (us_plus:V8HI (match_operand:V8HI 1 "register_operand" "%0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "paddusw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "subv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (minus:V16QI (match_operand:V16QI 1 "register_operand" "0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "psubb\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "subv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (minus:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "psubw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "subv4si3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (minus:V4SI (match_operand:V4SI 1 "register_operand" "0") + (match_operand:V4SI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "psubd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "subv2di3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (minus:V2DI (match_operand:V2DI 1 "register_operand" "0") + (match_operand:V2DI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "psubq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "sssubv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (ss_minus:V16QI (match_operand:V16QI 1 "register_operand" "0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "psubsb\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "sssubv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (ss_minus:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "psubsw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "ussubv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (us_minus:V16QI (match_operand:V16QI 1 "register_operand" "0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "psubusb\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "ussubv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (us_minus:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "psubusw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "mulv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (mult:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pmullw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseimul") + (set_attr "mode" "TI")]) + +(define_insn "smulv8hi3_highpart" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (truncate:V8HI + (lshiftrt:V8SI + (mult:V8SI (sign_extend:V8SI (match_operand:V8HI 1 "register_operand" "0")) + (sign_extend:V8SI (match_operand:V8HI 2 "nonimmediate_operand" "xm"))) + (const_int 16))))] + "TARGET_SSE2" + "pmulhw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseimul") + (set_attr "mode" "TI")]) + +(define_insn "umulv8hi3_highpart" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (truncate:V8HI + (lshiftrt:V8SI + (mult:V8SI (zero_extend:V8SI (match_operand:V8HI 1 "register_operand" "0")) + (zero_extend:V8SI (match_operand:V8HI 2 "nonimmediate_operand" "xm"))) + (const_int 16))))] + "TARGET_SSE2" + "pmulhuw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseimul") + (set_attr "mode" "TI")]) + +(define_insn "sse2_umulsidi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (mult:DI (zero_extend:DI (vec_select:SI + (match_operand:V2SI 1 "register_operand" "0") + (parallel [(const_int 0)]))) + (zero_extend:DI (vec_select:SI + (match_operand:V2SI 2 "nonimmediate_operand" "ym") + (parallel [(const_int 0)])))))] + "TARGET_SSE2" + "pmuludq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseimul") + (set_attr "mode" "TI")]) + +(define_insn "sse2_umulv2siv2di3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (mult:V2DI (zero_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "register_operand" "0") + (parallel [(const_int 0) (const_int 2)]))) + (zero_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 2 "nonimmediate_operand" "xm") + (parallel [(const_int 0) (const_int 2)])))))] + "TARGET_SSE2" + "pmuludq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseimul") + (set_attr "mode" "TI")]) + +(define_insn "sse2_pmaddwd" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (plus:V4SI + (mult:V4SI + (sign_extend:V4SI (vec_select:V4HI (match_operand:V8HI 1 "register_operand" "0") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6)]))) + (sign_extend:V4SI (vec_select:V4HI (match_operand:V8HI 2 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6)])))) + (mult:V4SI + (sign_extend:V4SI (vec_select:V4HI (match_dup 1) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)]))) + (sign_extend:V4SI (vec_select:V4HI (match_dup 2) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)]))))))] + "TARGET_SSE2" + "pmaddwd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +;; Same as pxor, but don't show input operands so that we don't think +;; they are live. +(define_insn "sse2_clrti" + [(set (match_operand:TI 0 "register_operand" "=x") (const_int 0))] + "TARGET_SSE2" +{ + if (get_attr_mode (insn) == MODE_TI) + return "pxor\t%0, %0"; else - emit_insn (gen_stack_protect_test_si (flags, operands[0], operands[1])); -#endif - emit_jump_insn (gen_beq (operands[2])); + return "xorps\t%0, %0"; +} + [(set_attr "type" "ssemov") + (set_attr "memory" "none") + (set (attr "mode") + (if_then_else + (ne (symbol_ref "optimize_size") + (const_int 0)) + (const_string "V4SF") + (const_string "TI")))]) + +;; MMX unsigned averages/sum of absolute differences + +(define_insn "sse2_uavgv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (ashiftrt:V16QI + (plus:V16QI (plus:V16QI + (match_operand:V16QI 1 "register_operand" "0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")) + (const_vector:V16QI [(const_int 1) (const_int 1) + (const_int 1) (const_int 1) + (const_int 1) (const_int 1) + (const_int 1) (const_int 1) + (const_int 1) (const_int 1) + (const_int 1) (const_int 1) + (const_int 1) (const_int 1) + (const_int 1) (const_int 1)])) + (const_int 1)))] + "TARGET_SSE2" + "pavgb\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "sse2_uavgv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (ashiftrt:V8HI + (plus:V8HI (plus:V8HI + (match_operand:V8HI 1 "register_operand" "0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")) + (const_vector:V8HI [(const_int 1) (const_int 1) + (const_int 1) (const_int 1) + (const_int 1) (const_int 1) + (const_int 1) (const_int 1)])) + (const_int 1)))] + "TARGET_SSE2" + "pavgw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +;; @@@ this isn't the right representation. +(define_insn "sse2_psadbw" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (unspec:V2DI [(match_operand:V16QI 1 "register_operand" "0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")] + UNSPEC_PSADBW))] + "TARGET_SSE2" + "psadbw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + + +;; MMX insert/extract/shuffle + +(define_insn "sse2_pinsrw" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (vec_merge:V8HI (match_operand:V8HI 1 "register_operand" "0") + (vec_duplicate:V8HI + (truncate:HI + (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (match_operand:SI 3 "const_0_to_255_operand" "N")))] + "TARGET_SSE2" + "pinsrw\t{%3, %2, %0|%0, %2, %3}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_pextrw" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (vec_select:HI (match_operand:V8HI 1 "register_operand" "x") + (parallel + [(match_operand:SI 2 "const_0_to_7_operand" "N")]))))] + "TARGET_SSE2" + "pextrw\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_pshufd" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")] + UNSPEC_SHUFFLE))] + "TARGET_SSE2" + "pshufd\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_pshuflw" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")] + UNSPEC_PSHUFLW))] + "TARGET_SSE2" + "pshuflw\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_pshufhw" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")] + UNSPEC_PSHUFHW))] + "TARGET_SSE2" + "pshufhw\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +;; MMX mask-generating comparisons + +(define_insn "eqv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (eq:V16QI (match_operand:V16QI 1 "register_operand" "0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pcmpeqb\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecmp") + (set_attr "mode" "TI")]) + +(define_insn "eqv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (eq:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pcmpeqw\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecmp") + (set_attr "mode" "TI")]) + +(define_insn "eqv4si3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (eq:V4SI (match_operand:V4SI 1 "register_operand" "0") + (match_operand:V4SI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pcmpeqd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecmp") + (set_attr "mode" "TI")]) + +(define_insn "gtv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (gt:V16QI (match_operand:V16QI 1 "register_operand" "0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pcmpgtb\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecmp") + (set_attr "mode" "TI")]) + +(define_insn "gtv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (gt:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pcmpgtw\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecmp") + (set_attr "mode" "TI")]) + +(define_insn "gtv4si3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (gt:V4SI (match_operand:V4SI 1 "register_operand" "0") + (match_operand:V4SI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pcmpgtd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecmp") + (set_attr "mode" "TI")]) + + +;; MMX max/min insns + +(define_insn "umaxv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (umax:V16QI (match_operand:V16QI 1 "register_operand" "0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pmaxub\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "smaxv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (smax:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pmaxsw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "uminv16qi3" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (umin:V16QI (match_operand:V16QI 1 "register_operand" "0") + (match_operand:V16QI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pminub\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + +(define_insn "sminv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (smin:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:V8HI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pminsw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseiadd") + (set_attr "mode" "TI")]) + + +;; MMX shifts + +(define_insn "ashrv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (ashiftrt:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "xi")))] + "TARGET_SSE2" + "psraw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "ashrv4si3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (ashiftrt:V4SI (match_operand:V4SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "xi")))] + "TARGET_SSE2" + "psrad\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "lshrv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (lshiftrt:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "xi")))] + "TARGET_SSE2" + "psrlw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "lshrv4si3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (lshiftrt:V4SI (match_operand:V4SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "xi")))] + "TARGET_SSE2" + "psrld\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "lshrv2di3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (lshiftrt:V2DI (match_operand:V2DI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "xi")))] + "TARGET_SSE2" + "psrlq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "ashlv8hi3" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (ashift:V8HI (match_operand:V8HI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "xi")))] + "TARGET_SSE2" + "psllw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "ashlv4si3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (ashift:V4SI (match_operand:V4SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "xi")))] + "TARGET_SSE2" + "pslld\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "ashlv2di3" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (ashift:V2DI (match_operand:V2DI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "xi")))] + "TARGET_SSE2" + "psllq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "ashrv8hi3_ti" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (ashiftrt:V8HI (match_operand:V8HI 1 "register_operand" "0") + (subreg:SI (match_operand:V2DI 2 "nonmemory_operand" "xi") 0)))] + "TARGET_SSE2" + "psraw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "ashrv4si3_ti" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (ashiftrt:V4SI (match_operand:V4SI 1 "register_operand" "0") + (subreg:SI (match_operand:V2DI 2 "nonmemory_operand" "xi") 0)))] + "TARGET_SSE2" + "psrad\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "lshrv8hi3_ti" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (lshiftrt:V8HI (match_operand:V8HI 1 "register_operand" "0") + (subreg:SI (match_operand:V2DI 2 "nonmemory_operand" "xi") 0)))] + "TARGET_SSE2" + "psrlw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "lshrv4si3_ti" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (lshiftrt:V4SI (match_operand:V4SI 1 "register_operand" "0") + (subreg:SI (match_operand:V2DI 2 "nonmemory_operand" "xi") 0)))] + "TARGET_SSE2" + "psrld\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "lshrv2di3_ti" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (lshiftrt:V2DI (match_operand:V2DI 1 "register_operand" "0") + (subreg:SI (match_operand:V2DI 2 "nonmemory_operand" "xi") 0)))] + "TARGET_SSE2" + "psrlq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "ashlv8hi3_ti" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (ashift:V8HI (match_operand:V8HI 1 "register_operand" "0") + (subreg:SI (match_operand:V2DI 2 "nonmemory_operand" "xi") 0)))] + "TARGET_SSE2" + "psllw\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "ashlv4si3_ti" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (ashift:V4SI (match_operand:V4SI 1 "register_operand" "0") + (subreg:SI (match_operand:V2DI 2 "nonmemory_operand" "xi") 0)))] + "TARGET_SSE2" + "pslld\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "ashlv2di3_ti" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (ashift:V2DI (match_operand:V2DI 1 "register_operand" "0") + (subreg:SI (match_operand:V2DI 2 "nonmemory_operand" "xi") 0)))] + "TARGET_SSE2" + "psllq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +;; See logical MMX insns for the reason for the unspec. Strictly speaking +;; we wouldn't need here it since we never generate TImode arithmetic. + +;; There has to be some kind of prize for the weirdest new instruction... +(define_insn "sse2_ashlti3" + [(set (match_operand:TI 0 "register_operand" "=x") + (unspec:TI + [(ashift:TI (match_operand:TI 1 "register_operand" "0") + (mult:SI (match_operand:SI 2 "immediate_operand" "i") + (const_int 8)))] UNSPEC_NOP))] + "TARGET_SSE2" + "pslldq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +(define_insn "sse2_lshrti3" + [(set (match_operand:TI 0 "register_operand" "=x") + (unspec:TI + [(lshiftrt:TI (match_operand:TI 1 "register_operand" "0") + (mult:SI (match_operand:SI 2 "immediate_operand" "i") + (const_int 8)))] UNSPEC_NOP))] + "TARGET_SSE2" + "psrldq\t{%2, %0|%0, %2}" + [(set_attr "type" "sseishft") + (set_attr "mode" "TI")]) + +;; SSE unpack + +(define_insn "sse2_unpckhpd" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_concat:V2DF + (vec_select:DF (match_operand:V2DF 1 "register_operand" "0") + (parallel [(const_int 1)])) + (vec_select:DF (match_operand:V2DF 2 "register_operand" "x") + (parallel [(const_int 1)]))))] + "TARGET_SSE2" + "unpckhpd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +(define_insn "sse2_unpcklpd" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_concat:V2DF + (vec_select:DF (match_operand:V2DF 1 "register_operand" "0") + (parallel [(const_int 0)])) + (vec_select:DF (match_operand:V2DF 2 "register_operand" "x") + (parallel [(const_int 0)]))))] + "TARGET_SSE2" + "unpcklpd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +;; MMX pack/unpack insns. + +(define_insn "sse2_packsswb" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (vec_concat:V16QI + (ss_truncate:V8QI (match_operand:V8HI 1 "register_operand" "0")) + (ss_truncate:V8QI (match_operand:V8HI 2 "register_operand" "x"))))] + "TARGET_SSE2" + "packsswb\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_packssdw" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (vec_concat:V8HI + (ss_truncate:V4HI (match_operand:V4SI 1 "register_operand" "0")) + (ss_truncate:V4HI (match_operand:V4SI 2 "register_operand" "x"))))] + "TARGET_SSE2" + "packssdw\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_packuswb" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (vec_concat:V16QI + (us_truncate:V8QI (match_operand:V8HI 1 "register_operand" "0")) + (us_truncate:V8QI (match_operand:V8HI 2 "register_operand" "x"))))] + "TARGET_SSE2" + "packuswb\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_punpckhbw" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (vec_merge:V16QI + (vec_select:V16QI (match_operand:V16QI 1 "register_operand" "0") + (parallel [(const_int 8) (const_int 0) + (const_int 9) (const_int 1) + (const_int 10) (const_int 2) + (const_int 11) (const_int 3) + (const_int 12) (const_int 4) + (const_int 13) (const_int 5) + (const_int 14) (const_int 6) + (const_int 15) (const_int 7)])) + (vec_select:V16QI (match_operand:V16QI 2 "register_operand" "x") + (parallel [(const_int 0) (const_int 8) + (const_int 1) (const_int 9) + (const_int 2) (const_int 10) + (const_int 3) (const_int 11) + (const_int 4) (const_int 12) + (const_int 5) (const_int 13) + (const_int 6) (const_int 14) + (const_int 7) (const_int 15)])) + (const_int 21845)))] + "TARGET_SSE2" + "punpckhbw\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_punpckhwd" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (vec_merge:V8HI + (vec_select:V8HI (match_operand:V8HI 1 "register_operand" "0") + (parallel [(const_int 4) (const_int 0) + (const_int 5) (const_int 1) + (const_int 6) (const_int 2) + (const_int 7) (const_int 3)])) + (vec_select:V8HI (match_operand:V8HI 2 "register_operand" "x") + (parallel [(const_int 0) (const_int 4) + (const_int 1) (const_int 5) + (const_int 2) (const_int 6) + (const_int 3) (const_int 7)])) + (const_int 85)))] + "TARGET_SSE2" + "punpckhwd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_punpckhdq" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (vec_merge:V4SI + (vec_select:V4SI (match_operand:V4SI 1 "register_operand" "0") + (parallel [(const_int 2) (const_int 0) + (const_int 3) (const_int 1)])) + (vec_select:V4SI (match_operand:V4SI 2 "register_operand" "x") + (parallel [(const_int 0) (const_int 2) + (const_int 1) (const_int 3)])) + (const_int 5)))] + "TARGET_SSE2" + "punpckhdq\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_punpcklbw" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (vec_merge:V16QI + (vec_select:V16QI (match_operand:V16QI 1 "register_operand" "0") + (parallel [(const_int 0) (const_int 8) + (const_int 1) (const_int 9) + (const_int 2) (const_int 10) + (const_int 3) (const_int 11) + (const_int 4) (const_int 12) + (const_int 5) (const_int 13) + (const_int 6) (const_int 14) + (const_int 7) (const_int 15)])) + (vec_select:V16QI (match_operand:V16QI 2 "register_operand" "x") + (parallel [(const_int 8) (const_int 0) + (const_int 9) (const_int 1) + (const_int 10) (const_int 2) + (const_int 11) (const_int 3) + (const_int 12) (const_int 4) + (const_int 13) (const_int 5) + (const_int 14) (const_int 6) + (const_int 15) (const_int 7)])) + (const_int 21845)))] + "TARGET_SSE2" + "punpcklbw\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_punpcklwd" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (vec_merge:V8HI + (vec_select:V8HI (match_operand:V8HI 1 "register_operand" "0") + (parallel [(const_int 0) (const_int 4) + (const_int 1) (const_int 5) + (const_int 2) (const_int 6) + (const_int 3) (const_int 7)])) + (vec_select:V8HI (match_operand:V8HI 2 "register_operand" "x") + (parallel [(const_int 4) (const_int 0) + (const_int 5) (const_int 1) + (const_int 6) (const_int 2) + (const_int 7) (const_int 3)])) + (const_int 85)))] + "TARGET_SSE2" + "punpcklwd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_punpckldq" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (vec_merge:V4SI + (vec_select:V4SI (match_operand:V4SI 1 "register_operand" "0") + (parallel [(const_int 0) (const_int 2) + (const_int 1) (const_int 3)])) + (vec_select:V4SI (match_operand:V4SI 2 "register_operand" "x") + (parallel [(const_int 2) (const_int 0) + (const_int 3) (const_int 1)])) + (const_int 5)))] + "TARGET_SSE2" + "punpckldq\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_punpcklqdq" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (vec_merge:V2DI + (vec_select:V2DI (match_operand:V2DI 2 "register_operand" "x") + (parallel [(const_int 1) + (const_int 0)])) + (match_operand:V2DI 1 "register_operand" "0") + (const_int 1)))] + "TARGET_SSE2" + "punpcklqdq\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_punpckhqdq" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (vec_merge:V2DI + (match_operand:V2DI 1 "register_operand" "0") + (vec_select:V2DI (match_operand:V2DI 2 "register_operand" "x") + (parallel [(const_int 1) + (const_int 0)])) + (const_int 1)))] + "TARGET_SSE2" + "punpckhqdq\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +;; SSE2 moves + +(define_insn "sse2_movapd" + [(set (match_operand:V2DF 0 "nonimmediate_operand" "=x,m") + (unspec:V2DF [(match_operand:V2DF 1 "nonimmediate_operand" "xm,x")] + UNSPEC_MOVA))] + "TARGET_SSE2 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "movapd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssemov") + (set_attr "mode" "V2DF")]) + +(define_insn "sse2_movupd" + [(set (match_operand:V2DF 0 "nonimmediate_operand" "=x,m") + (unspec:V2DF [(match_operand:V2DF 1 "nonimmediate_operand" "xm,x")] + UNSPEC_MOVU))] + "TARGET_SSE2 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "movupd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +(define_insn "sse2_movdqa" + [(set (match_operand:V16QI 0 "nonimmediate_operand" "=x,m") + (unspec:V16QI [(match_operand:V16QI 1 "nonimmediate_operand" "xm,x")] + UNSPEC_MOVA))] + "TARGET_SSE2 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "movdqa\t{%1, %0|%0, %1}" + [(set_attr "type" "ssemov") + (set_attr "mode" "TI")]) + +(define_insn "sse2_movdqu" + [(set (match_operand:V16QI 0 "nonimmediate_operand" "=x,m") + (unspec:V16QI [(match_operand:V16QI 1 "nonimmediate_operand" "xm,x")] + UNSPEC_MOVU))] + "TARGET_SSE2 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "movdqu\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_movdq2q" + [(set (match_operand:DI 0 "nonimmediate_operand" "=m,y") + (vec_select:DI (match_operand:V2DI 1 "register_operand" "x,x") + (parallel [(const_int 0)])))] + "TARGET_SSE2 && !TARGET_64BIT" + "@ + movq\t{%1, %0|%0, %1} + movdq2q\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_movdq2q_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=m,y,r") + (vec_select:DI (match_operand:V2DI 1 "register_operand" "x,x,x") + (parallel [(const_int 0)])))] + "TARGET_SSE2 && TARGET_64BIT" + "@ + movq\t{%1, %0|%0, %1} + movdq2q\t{%1, %0|%0, %1} + movd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_movq2dq" + [(set (match_operand:V2DI 0 "register_operand" "=x,?x") + (vec_concat:V2DI (match_operand:DI 1 "nonimmediate_operand" "m,y") + (const_int 0)))] + "TARGET_SSE2 && !TARGET_64BIT" + "@ + movq\t{%1, %0|%0, %1} + movq2dq\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt,ssemov") + (set_attr "mode" "TI")]) + +(define_insn "sse2_movq2dq_rex64" + [(set (match_operand:V2DI 0 "register_operand" "=x,?x,?x") + (vec_concat:V2DI (match_operand:DI 1 "nonimmediate_operand" "m,y,r") + (const_int 0)))] + "TARGET_SSE2 && TARGET_64BIT" + "@ + movq\t{%1, %0|%0, %1} + movq2dq\t{%1, %0|%0, %1} + movd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt,ssemov,ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "sse2_movq" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (vec_concat:V2DI (vec_select:DI + (match_operand:V2DI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0)])) + (const_int 0)))] + "TARGET_SSE2" + "movq\t{%1, %0|%0, %1}" + [(set_attr "type" "ssemov") + (set_attr "mode" "TI")]) + +(define_insn "sse2_loadd" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (vec_merge:V4SI + (vec_duplicate:V4SI (match_operand:SI 1 "nonimmediate_operand" "mr")) + (const_vector:V4SI [(const_int 0) + (const_int 0) + (const_int 0) + (const_int 0)]) + (const_int 1)))] + "TARGET_SSE2" + "movd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssemov") + (set_attr "mode" "TI")]) + +(define_insn "sse2_stored" + [(set (match_operand:SI 0 "nonimmediate_operand" "=mr") + (vec_select:SI + (match_operand:V4SI 1 "register_operand" "x") + (parallel [(const_int 0)])))] + "TARGET_SSE2" + "movd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssemov") + (set_attr "mode" "TI")]) + +(define_insn "sse2_movhpd" + [(set (match_operand:V2DF 0 "nonimmediate_operand" "=x,m") + (vec_merge:V2DF + (match_operand:V2DF 1 "nonimmediate_operand" "0,0") + (match_operand:V2DF 2 "nonimmediate_operand" "m,x") + (const_int 2)))] + "TARGET_SSE2 && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM)" + "movhpd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +(define_expand "sse2_loadsd" + [(match_operand:V2DF 0 "register_operand" "") + (match_operand:DF 1 "memory_operand" "")] + "TARGET_SSE2" +{ + emit_insn (gen_sse2_loadsd_1 (operands[0], operands[1], + CONST0_RTX (V2DFmode))); DONE; }) -(define_insn "stack_protect_test_si" - [(set (match_operand:CCZ 0 "flags_reg_operand" "") - (unspec:CCZ [(match_operand:SI 1 "memory_operand" "m") - (match_operand:SI 2 "memory_operand" "m")] - UNSPEC_SP_TEST)) - (clobber (match_scratch:SI 3 "=&r"))] - "" - "mov{l}\t{%1, %3|%3, %1}\;xor{l}\t{%2, %3|%3, %2}" - [(set_attr "type" "multi")]) +(define_insn "sse2_loadsd_1" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_merge:V2DF + (vec_duplicate:V2DF (match_operand:DF 1 "memory_operand" "m")) + (match_operand:V2DF 2 "const0_operand" "X") + (const_int 1)))] + "TARGET_SSE2" + "movsd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "DF")]) -(define_insn "stack_protect_test_di" - [(set (match_operand:CCZ 0 "flags_reg_operand" "") - (unspec:CCZ [(match_operand:DI 1 "memory_operand" "m") - (match_operand:DI 2 "memory_operand" "m")] - UNSPEC_SP_TEST)) - (clobber (match_scratch:DI 3 "=&r"))] - "TARGET_64BIT" - "mov{q}\t{%1, %3|%3, %1}\;xor{q}\t{%2, %3|%3, %2}" - [(set_attr "type" "multi")]) +(define_insn "sse2_movsd" + [(set (match_operand:V2DF 0 "nonimmediate_operand" "=x,x,m") + (vec_merge:V2DF + (match_operand:V2DF 1 "nonimmediate_operand" "0,0,0") + (match_operand:V2DF 2 "nonimmediate_operand" "x,m,x") + (const_int 1)))] + "TARGET_SSE2 && ix86_binary_operator_ok (UNKNOWN, V2DFmode, operands)" + "@movsd\t{%2, %0|%0, %2} + movlpd\t{%2, %0|%0, %2} + movlpd\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "DF,V2DF,V2DF")]) -(define_insn "stack_tls_protect_test_si" - [(set (match_operand:CCZ 0 "flags_reg_operand" "") - (unspec:CCZ [(match_operand:SI 1 "memory_operand" "m") - (match_operand:SI 2 "const_int_operand" "i")] - UNSPEC_SP_TLS_TEST)) - (clobber (match_scratch:SI 3 "=r"))] - "" - "mov{l}\t{%1, %3|%3, %1}\;xor{l}\t{%%gs:%P2, %3|%3, DWORD PTR %%gs:%P2}" - [(set_attr "type" "multi")]) +(define_insn "sse2_storesd" + [(set (match_operand:DF 0 "memory_operand" "=m") + (vec_select:DF + (match_operand:V2DF 1 "register_operand" "x") + (parallel [(const_int 0)])))] + "TARGET_SSE2" + "movsd\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "DF")]) -(define_insn "stack_tls_protect_test_di" - [(set (match_operand:CCZ 0 "flags_reg_operand" "") - (unspec:CCZ [(match_operand:DI 1 "memory_operand" "m") - (match_operand:DI 2 "const_int_operand" "i")] - UNSPEC_SP_TLS_TEST)) - (clobber (match_scratch:DI 3 "=r"))] - "TARGET_64BIT" - { - /* The kernel uses a different segment register for performance reasons; a - system call would not have to trash the userspace segment register, - which would be expensive */ - if (ix86_cmodel != CM_KERNEL) - return "mov{q}\t{%1, %3|%3, %1}\;xor{q}\t{%%fs:%P2, %3|%3, QWORD PTR %%fs:%P2}"; - else - return "mov{q}\t{%1, %3|%3, %1}\;xor{q}\t{%%gs:%P2, %3|%3, QWORD PTR %%gs:%P2}"; - } - [(set_attr "type" "multi")]) +(define_insn "sse2_shufpd" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm") + (match_operand:SI 3 "immediate_operand" "i")] + UNSPEC_SHUFFLE))] + "TARGET_SSE2" + ;; @@@ check operand order for intel/nonintel syntax + "shufpd\t{%3, %2, %0|%0, %2, %3}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "V2DF")]) + +(define_insn "sse2_clflush" + [(unspec_volatile [(match_operand 0 "address_operand" "p")] + UNSPECV_CLFLUSH)] + "TARGET_SSE2" + "clflush %0" + [(set_attr "type" "sse") + (set_attr "memory" "unknown")]) -(include "sse.md") -(include "mmx.md") -(include "sync.md") +(define_expand "sse2_mfence" + [(set (match_dup 0) + (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))] + "TARGET_SSE2" +{ + operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); + MEM_VOLATILE_P (operands[0]) = 1; +}) + +(define_insn "*mfence_insn" + [(set (match_operand:BLK 0 "" "") + (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))] + "TARGET_SSE2" + "mfence" + [(set_attr "type" "sse") + (set_attr "memory" "unknown")]) + +(define_expand "sse2_lfence" + [(set (match_dup 0) + (unspec:BLK [(match_dup 0)] UNSPEC_LFENCE))] + "TARGET_SSE2" +{ + operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); + MEM_VOLATILE_P (operands[0]) = 1; +}) + +(define_insn "*lfence_insn" + [(set (match_operand:BLK 0 "" "") + (unspec:BLK [(match_dup 0)] UNSPEC_LFENCE))] + "TARGET_SSE2" + "lfence" + [(set_attr "type" "sse") + (set_attr "memory" "unknown")]) + +;; SSE3 + +(define_insn "mwait" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "a") + (match_operand:SI 1 "register_operand" "c")] + UNSPECV_MWAIT)] + "TARGET_SSE3" + "mwait\t%0, %1" + [(set_attr "length" "3")]) + +(define_insn "monitor" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "a") + (match_operand:SI 1 "register_operand" "c") + (match_operand:SI 2 "register_operand" "d")] + UNSPECV_MONITOR)] + "TARGET_SSE3" + "monitor\t%0, %1, %2" + [(set_attr "length" "3")]) + +;; SSE3 arithmetic + +(define_insn "addsubv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")] + UNSPEC_ADDSUB))] + "TARGET_SSE3" + "addsubps\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V4SF")]) + +(define_insn "addsubv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")] + UNSPEC_ADDSUB))] + "TARGET_SSE3" + "addsubpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V2DF")]) + +(define_insn "haddv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")] + UNSPEC_HADD))] + "TARGET_SSE3" + "haddps\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V4SF")]) + +(define_insn "haddv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")] + UNSPEC_HADD))] + "TARGET_SSE3" + "haddpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V2DF")]) + +(define_insn "hsubv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")] + UNSPEC_HSUB))] + "TARGET_SSE3" + "hsubps\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V4SF")]) + +(define_insn "hsubv2df3" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "0") + (match_operand:V2DF 2 "nonimmediate_operand" "xm")] + UNSPEC_HSUB))] + "TARGET_SSE3" + "hsubpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sseadd") + (set_attr "mode" "V2DF")]) + +(define_insn "movshdup" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF + [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] UNSPEC_MOVSHDUP))] + "TARGET_SSE3" + "movshdup\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "V4SF")]) + +(define_insn "movsldup" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF + [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] UNSPEC_MOVSLDUP))] + "TARGET_SSE3" + "movsldup\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "V4SF")]) + +(define_insn "lddqu" + [(set (match_operand:V16QI 0 "register_operand" "=x") + (unspec:V16QI [(match_operand:V16QI 1 "memory_operand" "m")] + UNSPEC_LDQQU))] + "TARGET_SSE3" + "lddqu\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "TI")]) + +(define_insn "loadddup" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_duplicate:V2DF (match_operand:DF 1 "memory_operand" "m")))] + "TARGET_SSE3" + "movddup\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "DF")]) + +(define_insn "movddup" + [(set (match_operand:V2DF 0 "register_operand" "=x") + (vec_duplicate:V2DF + (vec_select:DF (match_operand:V2DF 1 "register_operand" "x") + (parallel [(const_int 0)]))))] + "TARGET_SSE3" + "movddup\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt") + (set_attr "mode" "DF")]) diff --git a/contrib/gcc/config/i386/x-cygwin b/contrib/gcc/config/i386/x-cygwin deleted file mode 100644 index cfd7758..0000000 --- a/contrib/gcc/config/i386/x-cygwin +++ /dev/null @@ -1,4 +0,0 @@ -host-cygwin.o : $(srcdir)/config/i386/host-cygwin.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h hosthooks.h $(HOSTHOOKS_DEF_H) toplev.h diagnostic.h - $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/config/i386/host-cygwin.c diff --git a/contrib/gcc/config/i386/x86-64.h b/contrib/gcc/config/i386/x86-64.h index cb92a21..6d1b811 100644 --- a/contrib/gcc/config/i386/x86-64.h +++ b/contrib/gcc/config/i386/x86-64.h @@ -1,5 +1,5 @@ /* OS independent definitions for AMD x86-64. - Copyright (C) 2001, 2005 Free Software Foundation, Inc. + Copyright (C) 2001 Free Software Foundation, Inc. Contributed by Bo Thorsen <bo@suse.de>. This file is part of GCC. @@ -16,8 +16,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* $FreeBSD$ */ #undef ASM_COMMENT_START #define ASM_COMMENT_START "#" @@ -49,40 +51,22 @@ Boston, MA 02110-1301, USA. */ #undef ASM_SPEC #define ASM_SPEC "%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} \ - %{Wa,*:%*} %{m32:--32} %{m64:--64}" + %{Wa,*:%*} %{m32:--32}" -#undef ASM_OUTPUT_ALIGNED_BSS #define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ - x86_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) - -#undef ASM_OUTPUT_ALIGNED_COMMON -#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ - x86_elf_aligned_common (FILE, NAME, SIZE, ALIGN); + asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) /* This is used to align code labels according to Intel recommendations. */ -#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN -#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \ - do { \ - if ((LOG) != 0) { \ - if ((MAX_SKIP) == 0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \ - else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \ - } \ - } while (0) -#endif - /* i386 System V Release 4 uses DWARF debugging info. x86-64 ABI specifies DWARF2. */ #define DWARF2_DEBUGGING_INFO 1 #define DWARF2_UNWIND_INFO 1 +/* Incorrectly autodetected in cross compilation. */ +#undef HAVE_AS_DWARF2_DEBUG_LINE +#define HAVE_AS_DWARF2_DEBUG_LINE 1 #undef PREFERRED_DEBUGGING_TYPE #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG - -#undef TARGET_ASM_SELECT_SECTION -#define TARGET_ASM_SELECT_SECTION x86_64_elf_select_section - -#undef TARGET_ASM_UNIQUE_SECTION -#define TARGET_ASM_UNIQUE_SECTION x86_64_elf_unique_section diff --git a/contrib/gcc/config/rs6000/freebsd.h b/contrib/gcc/config/rs6000/freebsd.h index edd267d..196e5ac 100644 --- a/contrib/gcc/config/rs6000/freebsd.h +++ b/contrib/gcc/config/rs6000/freebsd.h @@ -16,14 +16,20 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the - Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ + Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. */ /* Override the defaults, which exist to force the proper definition. */ #undef CPP_OS_DEFAULT_SPEC #define CPP_OS_DEFAULT_SPEC "%(cpp_os_freebsd)" +#undef CPP_OS_FREEBSD_SPEC +#define CPP_OS_FREEBSD_SPEC "\ + -D__PPC__ -D__ppc__ -D__PowerPC__ -D__powerpc__ \ + -Acpu=powerpc -Amachine=powerpc \ + %{fPIC|fpic|fPIE|fpie:-D__PIC__ -D__pic__} " + #undef STARTFILE_DEFAULT_SPEC #define STARTFILE_DEFAULT_SPEC "%(startfile_freebsd)" diff --git a/contrib/gcc/config/sparc/freebsd.h b/contrib/gcc/config/sparc/freebsd.h index 9e432a3..b077423 100644 --- a/contrib/gcc/config/sparc/freebsd.h +++ b/contrib/gcc/config/sparc/freebsd.h @@ -1,5 +1,5 @@ /* Definitions for Sun SPARC64 running FreeBSD using the ELF format - Copyright (C) 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc. Contributed by David E. O'Brien <obrien@FreeBSD.org> and BSDi. This file is part of GCC. @@ -16,8 +16,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $FreeBSD$ */ #undef SUBTARGET_EXTRA_SPECS #define SUBTARGET_EXTRA_SPECS \ @@ -28,11 +29,20 @@ Boston, MA 02110-1301, USA. */ #undef CPP_CPU64_DEFAULT_SPEC #define CPP_CPU64_DEFAULT_SPEC \ - "-D__sparc64__ -D__sparc_v9__ -D__sparcv9 -D__arch64__" + "-D__sparc64__ -D__sparc_v9__ -D__sparcv9 -D__sparc__ -D__arch64__" + +#undef FBSD_TARGET_CPU_CPP_BUILTINS +#define FBSD_TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + builtin_define ("__LP64__"); \ + } \ + while (0) #define LINK_SPEC "%(link_arch) \ %{!mno-relax:%{!r:-relax}} \ - %{p:%nconsider using `-pg' instead of `-p' with gprof(1)} \ + %{p:%nconsider using `-pg' instead of `-p' with gprof(1)} \ + %{Wl,*:%*} \ %{assert*} %{R*} %{rpath*} %{defsym*} \ %{shared:-Bshareable %{h*} %{soname*}} \ %{symbolic:-Bsymbolic} \ @@ -61,6 +71,10 @@ Boston, MA 02110-1301, USA. */ #undef LONG_DOUBLE_TYPE_SIZE #define LONG_DOUBLE_TYPE_SIZE (TARGET_LONG_DOUBLE_128 ? 128 : 64) +/* Constant which presents upper bound of the above value. */ +#undef MAX_LONG_DOUBLE_TYPE_SIZE +#define MAX_LONG_DOUBLE_TYPE_SIZE 128 + /* Define this to set long double type size to use in libgcc2.c, which can not depend on target_flags. */ #if defined(__arch64__) || defined(__LONG_DOUBLE_128__) @@ -71,6 +85,11 @@ Boston, MA 02110-1301, USA. */ /* Definitions for 64-bit SPARC running systems with ELF. */ +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ + {"long-double-64", -MASK_LONG_DOUBLE_128, N_("Use 64 bit long doubles") }, \ + {"long-double-128", MASK_LONG_DOUBLE_128, N_("Use 128 bit long doubles") }, + #undef TARGET_VERSION #define TARGET_VERSION fprintf (stderr, " (FreeBSD/sparc64 ELF)"); @@ -122,6 +141,14 @@ Boston, MA 02110-1301, USA. */ #define LOCAL_LABEL_PREFIX "." /* XXX2 */ +/* This is how to output a reference to an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#undef ASM_OUTPUT_INTERNAL_LABELREF +#define ASM_OUTPUT_INTERNAL_LABELREF(FILE,PREFIX,NUM) \ + fprintf (FILE, ".L%s%d", PREFIX, NUM) + +/* XXX2 */ /* This is how to store into the string LABEL the symbol_ref name of an internal numbered label where PREFIX is the class of label and NUM is the number within the class. @@ -150,9 +177,9 @@ Boston, MA 02110-1301, USA. */ /* #define DWARF_OFFSET_SIZE PTR_SIZE */ #undef ENDFILE_SPEC -#define ENDFILE_SPEC \ - "%{ffast-math|funsafe-math-optimizations:crtfastmath.o%s} " \ - FBSD_ENDFILE_SPEC +#define ENDFILE_SPEC \ + "%{ffast-math|funsafe-math-optimizations:crtfastmath.o%s}" \ + FBSD_ENDFILE_SPEC /* We use GNU ld so undefine this so that attribute((init_priority)) works. */ #undef CTORS_SECTION_ASM_OP diff --git a/contrib/gcc/config/x-linux b/contrib/gcc/config/x-linux index e4aa040..d14586b 100644 --- a/contrib/gcc/config/x-linux +++ b/contrib/gcc/config/x-linux @@ -1,4 +1,4 @@ host-linux.o : $(srcdir)/config/host-linux.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h hosthooks.h hosthooks-def.h $(HOOKS_H) + coretypes.h hosthooks.h hosthooks-def.h $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/host-linux.c diff --git a/contrib/gcc/configure b/contrib/gcc/configure index a248d39..91f9326 100755 --- a/contrib/gcc/configure +++ b/contrib/gcc/configure @@ -309,7 +309,7 @@ ac_includes_default="\ # include <unistd.h> #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os target_noncanonical build_libsubdir build_subdir host_subdir target_subdir GENINSRC CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT NO_MINUS_C_MINUS_O OUTPUT_OPTION CPP EGREP strict1_warn cxx_compat_warn warn_cflags WERROR nocommon_flag TREEBROWSER valgrind_path valgrind_path_defines valgrind_command coverage_flags enable_multilib enable_decimal_float enable_shared TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE CROSS_SYSTEM_HEADER_DIR onestep datarootdir docdir htmldir SET_MAKE AWK LN_S LN RANLIB ac_ct_RANLIB ranlib_flags INSTALL INSTALL_PROGRAM INSTALL_DATA make_compare_target have_mktemp_command MAKEINFO BUILD_INFO GENERATED_MANPAGES FLEX BISON NM AR stage1_cflags COLLECT2_LIBS GNAT_LIBEXC LDEXP_LIB TARGET_GETGROUPS_T LIBICONV LTLIBICONV LIBICONV_DEP manext objext gthread_flags extra_modes_file extra_opt_files USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT host_cc_for_libada CROSS ALL SYSTEM_HEADER_DIR inhibit_libc CC_FOR_BUILD BUILD_CFLAGS STMP_FIXINC STMP_FIXPROTO collect2 gcc_cv_as ORIGINAL_AS_FOR_TARGET gcc_cv_ld ORIGINAL_LD_FOR_TARGET gcc_cv_nm ORIGINAL_NM_FOR_TARGET gcc_cv_objdump libgcc_visibility GGC zlibdir zlibinc MAINT gcc_tooldir dollar slibdir objdir subdirs srcdir all_boot_languages all_compilers all_gtfiles all_gtfiles_files_langs all_gtfiles_files_files all_lang_makefrags all_lang_makefiles all_languages all_selected_languages all_stagestuff build_exeext build_install_headers_dir build_xm_file_list build_xm_include_list build_xm_defines check_languages cc_set_by_configure quoted_cc_set_by_configure cpp_install_dir xmake_file tmake_file extra_gcc_objs extra_headers_list extra_objs extra_parts extra_passes extra_programs float_h_file gcc_config_arguments gcc_gxx_include_dir host_exeext host_xm_file_list host_xm_include_list host_xm_defines out_host_hook_obj install lang_opt_files lang_specs_files lang_tree_files local_prefix md_file objc_boehm_gc out_file out_object_file stage_prefix_set_by_configure quoted_stage_prefix_set_by_configure thread_file tm_file_list tm_include_list tm_defines tm_p_file_list tm_p_include_list xm_file_list xm_include_list xm_defines c_target_objs cxx_target_objs target_cpu_default GMPLIBS GMPINC LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os build_subdir host_subdir target_subdir GENINSRC CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT NO_MINUS_C_MINUS_O OUTPUT_OPTION CPP GNATBIND ac_ct_GNATBIND strict1_warn warn_cflags WERROR nocommon_flag EGREP valgrind_path valgrind_path_defines valgrind_command coverage_flags enable_multilib enable_shared TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE CROSS_SYSTEM_HEADER_DIR onestep SET_MAKE AWK LN LN_S RANLIB ac_ct_RANLIB INSTALL INSTALL_PROGRAM INSTALL_DATA make_compare_target have_mktemp_command MAKEINFO BUILD_INFO GENERATED_MANPAGES FLEX BISON stage1_cflags COLLECT2_LIBS GNAT_LIBEXC LDEXP_LIB TARGET_GETGROUPS_T LIBICONV LIBICONV_DEP manext objext extra_modes_file FORBUILD PACKAGE VERSION USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS CROSS ALL SYSTEM_HEADER_DIR inhibit_libc BUILD_PREFIX BUILD_PREFIX_1 CC_FOR_BUILD BUILD_CFLAGS STMP_FIXINC STMP_FIXPROTO libgcc_visibility gthread_flags GGC zlibdir zlibinc MAINT gcc_tooldir dollar slibdir objdir subdirs srcdir all_boot_languages all_compilers all_gtfiles all_gtfiles_files_langs all_gtfiles_files_files all_lang_makefrags all_lang_makefiles all_languages all_stagestuff build_exeext build_install_headers_dir build_xm_file_list build_xm_include_list build_xm_defines check_languages cc_set_by_configure quoted_cc_set_by_configure cpp_install_dir xmake_file tmake_file extra_gcc_objs extra_headers_list extra_objs extra_parts extra_passes extra_programs float_h_file gcc_config_arguments gcc_gxx_include_dir libstdcxx_incdir gcc_version gcc_version_full gcc_version_trigger host_exeext host_xm_file_list host_xm_include_list host_xm_defines out_host_hook_obj install lang_opt_files lang_specs_files lang_tree_files local_prefix md_file objc_boehm_gc out_file out_object_file stage_prefix_set_by_configure quoted_stage_prefix_set_by_configure symbolic_link thread_file tm_file_list tm_include_list tm_defines tm_p_file_list tm_p_include_list xm_file_list xm_include_list xm_defines target_noncanonical c_target_objs cxx_target_objs target_cpu_default set_gcc_lib_path LIBOBJS LTLIBOBJS' ac_subst_files='language_hooks' # Initialize some variables set by options. @@ -770,14 +770,6 @@ ac_env_CPP_set=${CPP+set} ac_env_CPP_value=$CPP ac_cv_env_CPP_set=${CPP+set} ac_cv_env_CPP_value=$CPP -ac_env_GMPLIBS_set=${GMPLIBS+set} -ac_env_GMPLIBS_value=$GMPLIBS -ac_cv_env_GMPLIBS_set=${GMPLIBS+set} -ac_cv_env_GMPLIBS_value=$GMPLIBS -ac_env_GMPINC_set=${GMPINC+set} -ac_env_GMPINC_value=$GMPINC -ac_cv_env_GMPINC_set=${GMPINC+set} -ac_cv_env_GMPINC_value=$GMPINC # # Report the --help message. @@ -862,17 +854,14 @@ Optional Features: put copies of generated files in source dir intended for creating source tarballs for users without texinfo bison or flex. - --enable-werror-always enable -Werror always --enable-werror enable -Werror in bootstrap stage2 and later --enable-checking=LIST enable expensive run-time checks. With LIST, enable only specific categories of checks. - Categories are: yes,no,all,none,release. - Flags are: assert,fold,gc,gcac,misc, - rtlflag,rtl,runtime,tree,valgrind. - --enable-mapped-location location_t is fileline integer cookie + Categories are: misc,tree,rtl,rtlflag,gc,gcac,fold; + default is no checking --enable-coverage=LEVEL - enable compiler's code coverage collection. + enable compiler\'s code coverage collection. Use to measure compiler performance and locate unused parts of the compiler. With LEVEL, specify optimization. Values are opt, noopt, @@ -880,21 +869,15 @@ Optional Features: --enable-gather-detailed-mem-stats enable detailed memory allocation stats gathering --enable-multilib enable library support for multiple ABIs --enable-__cxa_atexit enable __cxa_atexit for C++ - --enable-decimal-float enable decimal float extension to C --enable-threads enable thread usage for target GCC --enable-threads=LIB use LIB thread package for target GCC - --enable-tls enable or disable generation of tls code - overriding the assembler check for tls support --enable-objc-gc enable the use of Boehm's garbage collector with the GNU Objective-C runtime --disable-shared don't provide a shared libgcc --enable-intermodule build the compiler in one step - --enable-languages=LIST specify which front-ends to build - --disable-rpath do not hardcode runtime library paths --enable-initfini-array use .init_array/.fini_array sections --enable-sjlj-exceptions arrange to use setjmp/longjmp exception handling - --enable-secureplt enable -msecure-plt by default for PowerPC --disable-win32-registry disable lookup of installation paths in the Registry on Windows hosts @@ -912,7 +895,6 @@ Optional Features: Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-build-libsubdir=DIR Directory where to find libraries for build system --with-local-prefix=DIR specifies directory to put local include --with-gxx-include-dir=DIR specifies directory to put g++ header files @@ -921,26 +903,17 @@ Optional Packages: (relative to PREFIX) as well as PREFIX/bin --with-gnu-ld arrange to work with GNU ld. --with-ld arrange to use the specified ld (full pathname) - --with-demangler-in-ld try to use demangler in GNU ld. --with-gnu-as arrange to work with GNU as --with-as arrange to use the specified as (full pathname) --with-stabs arrange to use stabs instead of host debug format --with-dwarf2 force the default debug format to be DWARF 2 - --with-build-sysroot=sysroot - use sysroot as the system root during the build --with-sysroot=DIR Search for usr/lib, usr/include, et al, within DIR. - --with-gnu-ld assume the C compiler uses GNU ld default=no - --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib - --without-libiconv-prefix don't search for libiconv in includedir and libdir + --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib --with-system-libunwind use installed libunwind - --with-long-double-128 Use 128-bit long double by default. - --with-gc={page,zone} choose the garbage collection mechanism to use + --with-gc={simple,page,zone} choose the garbage collection mechanism to use with the compiler --with-system-zlib use installed libz - --with-slibdir=DIR shared libraries in DIR [LIBDIR] - --with-datarootdir=DIR Use DIR as the data root [PREFIX/share] - --with-docdir=DIR Install documentation in DIR [DATAROOTDIR] - --with-htmldir=DIR html documentation in in DIR [DOCDIR] + --with-slibdir=DIR shared libraries in DIR LIBDIR Some influential environment variables: CC C compiler command @@ -950,8 +923,6 @@ Some influential environment variables: CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have headers in a nonstandard directory <include dir> CPP C preprocessor - GMPLIBS How to link GMP - GMPINC How to find GMP include files Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -1395,8 +1366,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers auto-host.h:config.in" -gcc_version=`cat $srcdir/BASE-VER` - # Determine the host, build, and target systems ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do @@ -1523,36 +1492,11 @@ esac esac - - # Determine the target- and build-specific subdirectories - -# post-stage1 host modules use a different CC_FOR_BUILD so, in order to -# have matching libraries, they should use host libraries: Makefile.tpl -# arranges to pass --with-build-libsubdir=$(HOST_SUBDIR). -# However, they still use the build modules, because the corresponding -# host modules (e.g. bison) are only built for the host when bootstrap -# finishes. So: -# - build_subdir is where we find build modules, and never changes. -# - build_libsubdir is where we find build libraries, and can be overridden. - -# Prefix 'build-' so this never conflicts with target_subdir. + # Prefix 'build-' so this never conflicts with target_subdir. build_subdir="build-${build_noncanonical}" - -# Check whether --with-build-libsubdir or --without-build-libsubdir was given. -if test "${with_build_libsubdir+set}" = set; then - withval="$with_build_libsubdir" - build_libsubdir="$withval" -else - build_libsubdir="$build_subdir" -fi; -# --srcdir=. covers the toplevel, while "test -d" covers the subdirectories -if ( test $srcdir = . && test -d gcc ) \ - || test -d $srcdir/../host-${host_noncanonical}; then - host_subdir="host-${host_noncanonical}" -else - host_subdir=. -fi +# Not really a subdirectory, but here for completeness. +host_subdir=. # No prefix. target_subdir=${target_noncanonical} @@ -1677,16 +1621,12 @@ no) ;; esac fi; -# This logic must match libstdc++-v3/acinclude.m4:GLIBCXX_EXPORT_INSTALL_INFO. if test x${gcc_gxx_include_dir} = x; then if test x${enable_version_specific_runtime_libs} = xyes; then gcc_gxx_include_dir='${libsubdir}/include/c++' else - libstdcxx_incdir='include/c++/$(version)' - if test x$host != x$target; then - libstdcxx_incdir="$target_alias/$libstdcxx_incdir" - fi - gcc_gxx_include_dir="\$(libsubdir)/\$(unlibsubdir)/..\`echo \$(exec_prefix) | sed -e 's|^\$(prefix)||' -e 's|/[^/]*|/..|g'\`/$libstdcxx_incdir" + topsrcdir=${srcdir}/.. . ${srcdir}/../config.if + gcc_gxx_include_dir="\$(libsubdir)/\$(unlibsubdir)/..\`echo \$(exec_prefix) | sed -e 's|^\$(prefix)||' -e 's|/[^/]*|/..|g'\`/include/"${libstdcxx_incdir} fi fi @@ -1752,9 +1692,8 @@ if test "${with_ld+set}" = set; then fi; if test x"${DEFAULT_LINKER+set}" = x"set"; then if test ! -x "$DEFAULT_LINKER"; then - { { echo "$as_me:$LINENO: error: cannot execute: $DEFAULT_LINKER: check --with-ld or env. var. DEFAULT_LINKER" >&5 -echo "$as_me: error: cannot execute: $DEFAULT_LINKER: check --with-ld or env. var. DEFAULT_LINKER" >&2;} - { (exit 1); exit 1; }; } + { echo "$as_me:$LINENO: WARNING: cannot execute: $DEFAULT_LINKER: check --with-ld or env. var. DEFAULT_LINKER" >&5 +echo "$as_me: WARNING: cannot execute: $DEFAULT_LINKER: check --with-ld or env. var. DEFAULT_LINKER" >&2;} elif $DEFAULT_LINKER -v < /dev/null 2>&1 | grep GNU > /dev/null; then gnu_ld_flag=yes fi @@ -1780,16 +1719,6 @@ else echo "${ECHO_T}no" >&6 fi -# With demangler in GNU ld - -# Check whether --with-demangler-in-ld or --without-demangler-in-ld was given. -if test "${with_demangler_in_ld+set}" = set; then - withval="$with_demangler_in_ld" - demangler_in_ld="$with_demangler_in_ld" -else - demangler_in_ld=no -fi; - # ---------------------- # Find default assembler # ---------------------- @@ -1812,9 +1741,8 @@ if test "${with_as+set}" = set; then fi; if test x"${DEFAULT_ASSEMBLER+set}" = x"set"; then if test ! -x "$DEFAULT_ASSEMBLER"; then - { { echo "$as_me:$LINENO: error: cannot execute: $DEFAULT_ASSEMBLER: check --with-as or env. var. DEFAULT_ASSEMBLER" >&5 -echo "$as_me: error: cannot execute: $DEFAULT_ASSEMBLER: check --with-as or env. var. DEFAULT_ASSEMBLER" >&2;} - { (exit 1); exit 1; }; } + { echo "$as_me:$LINENO: WARNING: cannot execute: $DEFAULT_ASSEMBLER: check --with-as or env. var. DEFAULT_ASSEMBLER" >&5 +echo "$as_me: WARNING: cannot execute: $DEFAULT_ASSEMBLER: check --with-as or env. var. DEFAULT_ASSEMBLER" >&2;} elif $DEFAULT_ASSEMBLER -v < /dev/null 2>&1 | grep GNU > /dev/null; then gas_flag=yes fi @@ -2874,22 +2802,6 @@ _ACEOF fi -# expand $ac_aux_dir to an absolute path -am_aux_dir=`cd $ac_aux_dir && pwd` - -# FIXME: we rely on the cache variable name because -# there is no other way. -set dummy $CC -ac_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` -if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi - # autoconf is lame and doesn't give us any substitution variable for this. if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = no"; then NO_MINUS_C_MINUS_O=yes @@ -2899,18 +2811,68 @@ fi -# Remove the -O2: for historical reasons, unless bootstrapping we prefer -# optimizations to be activated explicitly by the toplevel. -case "$CC" in - */prev-gcc/xgcc*) ;; - *) CFLAGS=`echo $CFLAGS | sed "s/-O[s0-9]* *//" ` ;; -esac - - # ------------------------- # Check C compiler features # ------------------------- + +echo "$as_me:$LINENO: checking whether ${CC-cc} accepts -Wno-long-long" >&5 +echo $ECHO_N "checking whether ${CC-cc} accepts -Wno-long-long... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_no_long_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + save_CFLAGS="$CFLAGS" +CFLAGS="-Wno-long-long" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_no_long_long=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_no_long_long=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="$save_CFLAGS" +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_no_long_long" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_no_long_long" >&6 + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3145,7 +3107,6 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - echo "$as_me:$LINENO: checking for inline" >&5 echo $ECHO_N "checking for inline... $ECHO_C" >&6 if test "${ac_cv_c_inline+set}" = set; then @@ -3218,26 +3179,9 @@ _ACEOF esac -# sizeof(char) is 1 by definition. - -echo "$as_me:$LINENO: checking for egrep" >&5 -echo $ECHO_N "checking for egrep... $ECHO_C" >&6 -if test "${ac_cv_prog_egrep+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if echo a | (grep -E '(a|b)') >/dev/null 2>&1 - then ac_cv_prog_egrep='grep -E' - else ac_cv_prog_egrep='egrep' - fi -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 -echo "${ECHO_T}$ac_cv_prog_egrep" >&6 - EGREP=$ac_cv_prog_egrep - - -echo "$as_me:$LINENO: checking for ANSI C header files" >&5 -echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 -if test "${ac_cv_header_stdc+set}" = set; then +echo "$as_me:$LINENO: checking for long long int" >&5 +echo $ECHO_N "checking for long long int... $ECHO_C" >&6 +if test "${ac_cv_c_long_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF @@ -3246,15 +3190,11 @@ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <float.h> int main () { - +long long int i; ; return 0; } @@ -3281,143 +3221,27 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_header_stdc=yes + ac_cv_c_long_long=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_header_stdc=no +ac_cv_c_long_long=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <string.h> - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then - : -else - ac_cv_header_stdc=no -fi -rm -f conftest* - fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <stdlib.h> - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then - : -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then - : -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <ctype.h> -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - exit(2); - exit (0); -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -ac_cv_header_stdc=no -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 -echo "${ECHO_T}$ac_cv_header_stdc" >&6 -if test $ac_cv_header_stdc = yes; then +echo "$as_me:$LINENO: result: $ac_cv_c_long_long" >&5 +echo "${ECHO_T}$ac_cv_c_long_long" >&6 + if test $ac_cv_c_long_long = yes; then cat >>confdefs.h <<\_ACEOF -#define STDC_HEADERS 1 +#define HAVE_LONG_LONG 1 _ACEOF -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. - - - - - - - - - -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then + fi +echo "$as_me:$LINENO: checking for __int64" >&5 +echo $ECHO_N "checking for __int64... $ECHO_C" >&6 +if test "${ac_cv_c___int64+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF @@ -3426,72 +3250,11 @@ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default - -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - eval "$as_ac_Header=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -eval "$as_ac_Header=no" -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - -echo "$as_me:$LINENO: checking for void *" >&5 -echo $ECHO_N "checking for void *... $ECHO_C" >&6 -if test "${ac_cv_type_void_p+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default int main () { -if ((void * *) 0) - return 0; -if (sizeof (void *)) - return 0; +__int64 i; ; return 0; } @@ -3518,84 +3281,41 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_void_p=yes + ac_cv_c___int64=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_type_void_p=no +ac_cv_c___int64=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_type_void_p" >&5 -echo "${ECHO_T}$ac_cv_type_void_p" >&6 +echo "$as_me:$LINENO: result: $ac_cv_c___int64" >&5 +echo "${ECHO_T}$ac_cv_c___int64" >&6 + if test $ac_cv_c___int64 = yes; then -echo "$as_me:$LINENO: checking size of void *" >&5 -echo $ECHO_N "checking size of void *... $ECHO_C" >&6 -if test "${ac_cv_sizeof_void_p+set}" = set; then +cat >>confdefs.h <<\_ACEOF +#define HAVE___INT64 1 +_ACEOF + + fi + +echo "$as_me:$LINENO: checking for built-in _Bool" >&5 +echo $ECHO_N "checking for built-in _Bool... $ECHO_C" >&6 +if test "${gcc_cv_c__bool+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - if test "$ac_cv_type_void_p" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (void *))) >= 0)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default int main () { -static int test_array [1 - 2 * !(((long) (sizeof (void *))) <= $ac_mid)]; -test_array [0] = 0 - +_Bool foo; ; return 0; } @@ -3622,143 +3342,48 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_hi=$ac_mid; break + gcc_cv_c__bool=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` +gcc_cv_c__bool=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (void *))) < 0)]; -test_array [0] = 0 +fi +echo "$as_me:$LINENO: result: $gcc_cv_c__bool" >&5 +echo "${ECHO_T}$gcc_cv_c__bool" >&6 +if test $gcc_cv_c__bool = yes; then - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ +cat >>confdefs.h <<\_ACEOF +#define HAVE__BOOL 1 _ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (void *))) >= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + +# sizeof(char) is 1 by definition. +echo "$as_me:$LINENO: checking size of void *" >&5 +echo $ECHO_N "checking size of void *... $ECHO_C" >&6 +if test "${ac_cv_sizeof_void_p+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default +#include "confdefs.h" +#include <sys/types.h> + + int main () { -static int test_array [1 - 2 * !(((long) (sizeof (void *))) <= $ac_mid)]; -test_array [0] = 0 - +switch (0) case 0: case (sizeof (void *) == $ac_size):; ; return 0; } @@ -3785,394 +3410,51 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_hi=$ac_mid + ac_cv_sizeof_void_p=$ac_size else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + if test x$ac_cv_sizeof_void_p != x ; then break; fi done -case $ac_lo in -?*) ac_cv_sizeof_void_p=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (void *), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (void *), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (void *)); } -unsigned long ulongval () { return (long) (sizeof (void *)); } -#include <stdio.h> -#include <stdlib.h> -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (void *))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (void *)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (void *)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_void_p=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +fi -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (void *), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (void *), 77 -See \`config.log' for more details." >&2;} +if test x$ac_cv_sizeof_void_p = x ; then + { { echo "$as_me:$LINENO: error: cannot determine a size for void *" >&5 +echo "$as_me: error: cannot determine a size for void *" >&2;} { (exit 1); exit 1; }; } fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_void_p=0 -fi -fi echo "$as_me:$LINENO: result: $ac_cv_sizeof_void_p" >&5 echo "${ECHO_T}$ac_cv_sizeof_void_p" >&6 + cat >>confdefs.h <<_ACEOF #define SIZEOF_VOID_P $ac_cv_sizeof_void_p _ACEOF -echo "$as_me:$LINENO: checking for short" >&5 -echo $ECHO_N "checking for short... $ECHO_C" >&6 -if test "${ac_cv_type_short+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((short *) 0) - return 0; -if (sizeof (short)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_short=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_type_short=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5 -echo "${ECHO_T}$ac_cv_type_short" >&6 - echo "$as_me:$LINENO: checking size of short" >&5 echo $ECHO_N "checking size of short... $ECHO_C" >&6 if test "${ac_cv_sizeof_short+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - if test "$ac_cv_type_short" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (short))) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (short))) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF + for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (short))) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +#include "confdefs.h" +#include <sys/types.h> -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default int main () { -static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)]; -test_array [0] = 0 - +switch (0) case 0: case (sizeof (short) == $ac_size):; ; return 0; } @@ -4199,231 +3481,51 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_hi=$ac_mid + ac_cv_sizeof_short=$ac_size else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + if test x$ac_cv_sizeof_short != x ; then break; fi done -case $ac_lo in -?*) ac_cv_sizeof_short=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (short), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (short)); } -unsigned long ulongval () { return (long) (sizeof (short)); } -#include <stdio.h> -#include <stdlib.h> -int -main () -{ - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (short))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (short)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (short)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_short=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +fi -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (short), 77 -See \`config.log' for more details." >&2;} +if test x$ac_cv_sizeof_short = x ; then + { { echo "$as_me:$LINENO: error: cannot determine a size for short" >&5 +echo "$as_me: error: cannot determine a size for short" >&2;} { (exit 1); exit 1; }; } fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_short=0 -fi -fi echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5 echo "${ECHO_T}$ac_cv_sizeof_short" >&6 + cat >>confdefs.h <<_ACEOF #define SIZEOF_SHORT $ac_cv_sizeof_short _ACEOF -echo "$as_me:$LINENO: checking for int" >&5 -echo $ECHO_N "checking for int... $ECHO_C" >&6 -if test "${ac_cv_type_int+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((int *) 0) - return 0; -if (sizeof (int)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_int=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_type_int=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5 -echo "${ECHO_T}$ac_cv_type_int" >&6 - echo "$as_me:$LINENO: checking size of int" >&5 echo $ECHO_N "checking size of int... $ECHO_C" >&6 if test "${ac_cv_sizeof_int+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - if test "$ac_cv_type_int" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF + for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (int))) >= 0)]; -test_array [0] = 0 +#include "confdefs.h" +#include <sys/types.h> + - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default int main () { -static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)]; -test_array [0] = 0 - +switch (0) case 0: case (sizeof (int) == $ac_size):; ; return 0; } @@ -4450,143 +3552,51 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_hi=$ac_mid; break + ac_cv_sizeof_int=$ac_size else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if test x$ac_cv_sizeof_int != x ; then break; fi +done -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (int))) < 0)]; -test_array [0] = 0 +fi - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (int))) >= $ac_mid)]; -test_array [0] = 0 +if test x$ac_cv_sizeof_int = x ; then + { { echo "$as_me:$LINENO: error: cannot determine a size for int" >&5 +echo "$as_me: error: cannot determine a size for int" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 +echo "${ECHO_T}$ac_cv_sizeof_int" >&6 - ; - return 0; -} +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` +echo "$as_me:$LINENO: checking size of long" >&5 +echo $ECHO_N "checking size of long... $ECHO_C" >&6 +if test "${ac_cv_sizeof_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default +#include "confdefs.h" +#include <sys/types.h> + + int main () { -static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)]; -test_array [0] = 0 - +switch (0) case 0: case (sizeof (long) == $ac_size):; ; return 0; } @@ -4613,127 +3623,52 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_hi=$ac_mid + ac_cv_sizeof_long=$ac_size else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + if test x$ac_cv_sizeof_long != x ; then break; fi done -case $ac_lo in -?*) ac_cv_sizeof_int=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (int), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (int)); } -unsigned long ulongval () { return (long) (sizeof (int)); } -#include <stdio.h> -#include <stdlib.h> -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (int))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (int)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (int)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_int=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +fi -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (int), 77 -See \`config.log' for more details." >&2;} +if test x$ac_cv_sizeof_long = x ; then + { { echo "$as_me:$LINENO: error: cannot determine a size for long" >&5 +echo "$as_me: error: cannot determine a size for long" >&2;} { (exit 1); exit 1; }; } fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_int=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 -echo "${ECHO_T}$ac_cv_sizeof_int" >&6 +echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 +echo "${ECHO_T}$ac_cv_sizeof_long" >&6 + cat >>confdefs.h <<_ACEOF -#define SIZEOF_INT $ac_cv_sizeof_int +#define SIZEOF_LONG $ac_cv_sizeof_long _ACEOF -echo "$as_me:$LINENO: checking for long" >&5 -echo $ECHO_N "checking for long... $ECHO_C" >&6 -if test "${ac_cv_type_long+set}" = set; then +if test $ac_cv_c_long_long = yes; then + echo "$as_me:$LINENO: checking size of long long" >&5 +echo $ECHO_N "checking size of long long... $ECHO_C" >&6 +if test "${ac_cv_sizeof_long_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else + for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default +#include "confdefs.h" +#include <sys/types.h> + + int main () { -if ((long *) 0) - return 0; -if (sizeof (long)) - return 0; +switch (0) case 0: case (sizeof (long long) == $ac_size):; ; return 0; } @@ -4760,182 +3695,53 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_long=yes + ac_cv_sizeof_long_long=$ac_size else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_type_long=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + if test x$ac_cv_sizeof_long_long != x ; then break; fi +done + fi -echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5 -echo "${ECHO_T}$ac_cv_type_long" >&6 -echo "$as_me:$LINENO: checking size of long" >&5 -echo $ECHO_N "checking size of long... $ECHO_C" >&6 -if test "${ac_cv_sizeof_long+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test "$ac_cv_type_long" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) >= 0)]; -test_array [0] = 0 +if test x$ac_cv_sizeof_long_long = x ; then + { { echo "$as_me:$LINENO: error: cannot determine a size for long long" >&5 +echo "$as_me: error: cannot determine a size for long long" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_long" >&5 +echo "${ECHO_T}$ac_cv_sizeof_long_long" >&6 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long _ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done +if test $ac_cv_c___int64 = yes; then + echo "$as_me:$LINENO: checking size of __int64" >&5 +echo $ECHO_N "checking size of __int64... $ECHO_C" >&6 +if test "${ac_cv_sizeof___int64+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -cat >conftest.$ac_ext <<_ACEOF + for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) < 0)]; -test_array [0] = 0 +#include "confdefs.h" +#include <sys/types.h> + - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default int main () { -static int test_array [1 - 2 * !(((long) (sizeof (long))) >= $ac_mid)]; -test_array [0] = 0 - +switch (0) case 0: case (sizeof (__int64) == $ac_size):; ; return 0; } @@ -4962,835 +3768,319 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_lo=$ac_mid; break + ac_cv_sizeof___int64=$ac_size else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if test x$ac_cv_sizeof___int64 != x ; then break; fi +done -ac_lo= ac_hi= fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test x$ac_cv_sizeof___int64 = x ; then + { { echo "$as_me:$LINENO: error: cannot determine a size for __int64" >&5 +echo "$as_me: error: cannot determine a size for __int64" >&2;} + { (exit 1); exit 1; }; } fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; -test_array [0] = 0 +echo "$as_me:$LINENO: result: $ac_cv_sizeof___int64" >&5 +echo "${ECHO_T}$ac_cv_sizeof___int64" >&6 - ; - return 0; -} +cat >>confdefs.h <<_ACEOF +#define SIZEOF___INT64 $ac_cv_sizeof___int64 _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` + fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_long=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (long), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (long)); } -unsigned long ulongval () { return (long) (sizeof (long)); } -#include <stdio.h> -#include <stdlib.h> -int -main () -{ - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (long))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (long)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (long)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); +# ----------------- +# Find Ada compiler +# ----------------- - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_long=`cat conftest.val` +# See if GNAT has been installed + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gnatbind", so it can be a program name with args. +set dummy ${ac_tool_prefix}gnatbind; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_GNATBIND+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if test -n "$GNATBIND"; then + ac_cv_prog_GNATBIND="$GNATBIND" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_GNATBIND="${ac_tool_prefix}gnatbind" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (long), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi -rm -f conftest.val +GNATBIND=$ac_cv_prog_GNATBIND +if test -n "$GNATBIND"; then + echo "$as_me:$LINENO: result: $GNATBIND" >&5 +echo "${ECHO_T}$GNATBIND" >&6 else - ac_cv_sizeof_long=0 -fi + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 -echo "${ECHO_T}$ac_cv_sizeof_long" >&6 -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF - -echo "$as_me:$LINENO: checking for long long" >&5 -echo $ECHO_N "checking for long long... $ECHO_C" >&6 -if test "${ac_cv_type_long_long+set}" = set; then +fi +if test -z "$ac_cv_prog_GNATBIND"; then + ac_ct_GNATBIND=$GNATBIND + # Extract the first word of "gnatbind", so it can be a program name with args. +set dummy gnatbind; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_GNATBIND+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((long long *) 0) - return 0; -if (sizeof (long long)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_long_long=yes + if test -n "$ac_ct_GNATBIND"; then + ac_cv_prog_ac_ct_GNATBIND="$ac_ct_GNATBIND" # Let the user override the test. else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_GNATBIND="gnatbind" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done -ac_cv_type_long_long=no + test -z "$ac_cv_prog_ac_ct_GNATBIND" && ac_cv_prog_ac_ct_GNATBIND="no" fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5 -echo "${ECHO_T}$ac_cv_type_long_long" >&6 -if test $ac_cv_type_long_long = yes; then +ac_ct_GNATBIND=$ac_cv_prog_ac_ct_GNATBIND +if test -n "$ac_ct_GNATBIND"; then + echo "$as_me:$LINENO: result: $ac_ct_GNATBIND" >&5 +echo "${ECHO_T}$ac_ct_GNATBIND" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi -cat >>confdefs.h <<_ACEOF -#define HAVE_LONG_LONG 1 -_ACEOF + GNATBIND=$ac_ct_GNATBIND +else + GNATBIND="$ac_cv_prog_GNATBIND" +fi -echo "$as_me:$LINENO: checking for long long" >&5 -echo $ECHO_N "checking for long long... $ECHO_C" >&6 -if test "${ac_cv_type_long_long+set}" = set; then +echo "$as_me:$LINENO: checking whether compiler driver understands Ada" >&5 +echo $ECHO_N "checking whether compiler driver understands Ada... $ECHO_C" >&6 +if test "${gcc_cv_cc_supports_ada+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((long long *) 0) - return 0; -if (sizeof (long long)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_long_long=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_type_long_long=no + cat >conftest.adb <<EOF +procedure conftest is begin null; end conftest; +EOF +gcc_cv_cc_supports_ada=no +# There is a bug in old released versions of GCC which causes the +# driver to exit successfully when the appropriate language module +# has not been installed. This is fixed in 2.95.4, 3.0.2, and 3.1. +# Therefore we must check for the error message as well as an +# unsuccessful exit. +# Other compilers, like HP Tru64 UNIX cc, exit successfully when +# given a .adb file, but produce no object file. So we must check +# if an object file was really produced to guard against this. +errors=`(${CC} -c conftest.adb) 2>&1 || echo failure` +if test x"$errors" = x && test -f conftest.$ac_objext; then + gcc_cv_cc_supports_ada=yes + break fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f conftest.* fi -echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5 -echo "${ECHO_T}$ac_cv_type_long_long" >&6 +echo "$as_me:$LINENO: result: $gcc_cv_cc_supports_ada" >&5 +echo "${ECHO_T}$gcc_cv_cc_supports_ada" >&6 -echo "$as_me:$LINENO: checking size of long long" >&5 -echo $ECHO_N "checking size of long long... $ECHO_C" >&6 -if test "${ac_cv_sizeof_long_long+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +if test x$GNATBIND != xno && test x$gcc_cv_cc_supports_ada != xno; then + have_gnat=yes else - if test "$ac_cv_type_long_long" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long long))) >= 0)]; -test_array [0] = 0 + have_gnat=no +fi - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long long))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +# --------------------- +# Warnings and checking +# --------------------- -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` +strict1_warn= +if test $ac_cv_prog_cc_no_long_long = yes ; then + strict1_warn="-pedantic -Wno-long-long" fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long long))) < 0)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long long))) >= $ac_mid)]; -test_array [0] = 0 +# If the native compiler is GCC, we can enable warnings even in stage1. +# That's useful for people building cross-compilers, or just running a +# quick `make'. +warn_cflags= +if test "x$GCC" = "xyes"; then + warn_cflags='$(GCC_WARN_CFLAGS)' +fi - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +# Enable -Werror in bootstrap stage2 and later. +# Change the default to "no" on release branches. +# Check whether --enable-werror or --disable-werror was given. +if test "${enable_werror+set}" = set; then + enableval="$enable_werror" -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +else + enable_werror=no +fi; +if test x$enable_werror = xyes ; then + WERROR=-Werror fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long long))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_long_long=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (long long), 77 -See \`config.log' for more details." >&2;} +# Enable expensive internal checks +# Check whether --enable-checking or --disable-checking was given. +if test "${enable_checking+set}" = set; then + enableval="$enable_checking" + ac_checking= +ac_tree_checking= +ac_rtl_checking= +ac_rtlflag_checking= +ac_gc_checking= +ac_gc_always_collect= +ac_fold_checking= +case "${enableval}" in +yes) ac_checking=1 ; ac_tree_checking=1 ; ac_gc_checking=1 ; + ac_rtlflag_checking=1 ;; +no) ;; +*) IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="$IFS," + set fnord $enableval; shift + IFS="$ac_save_IFS" + for check + do + case $check in + misc) ac_checking=1 ;; + tree) ac_tree_checking=1 ;; + rtlflag) ac_rtlflag_checking=1 ;; + rtl) ac_rtl_checking=1 ;; + gc) ac_gc_checking=1 ;; + gcac) ac_gc_always_collect=1 ;; + fold) ac_fold_checking=1 ;; + valgrind) ac_checking_valgrind=1 ;; + *) { { echo "$as_me:$LINENO: error: unknown check category $check" >&5 +echo "$as_me: error: unknown check category $check" >&2;} { (exit 1); exit 1; }; } ;; + esac + done + ;; esac + else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ + # By default, disable all checks for release versions of GCC. +ac_checking=; ac_tree_checking=; ac_gc_checking=; ac_rtlflag_checking=; +fi; +nocommon_flag="" +if test x$ac_checking != x ; then + +cat >>confdefs.h <<\_ACEOF +#define ENABLE_CHECKING 1 _ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (long long)); } -unsigned long ulongval () { return (long) (sizeof (long long)); } -#include <stdio.h> -#include <stdlib.h> -int -main () -{ - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (long long))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (long long)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (long long)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); + nocommon_flag=-fno-common +fi - ; - return 0; -} +if test x$ac_tree_checking != x ; then + +cat >>confdefs.h <<\_ACEOF +#define ENABLE_TREE_CHECKING 1 _ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_long_long=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long long), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (long long), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi fi -rm -f conftest.val -else - ac_cv_sizeof_long_long=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_long" >&5 -echo "${ECHO_T}$ac_cv_sizeof_long_long" >&6 -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long -_ACEOF +if test x$ac_rtl_checking != x ; then +cat >>confdefs.h <<\_ACEOF +#define ENABLE_RTL_CHECKING 1 +_ACEOF fi +if test x$ac_rtlflag_checking != x ; then -echo "$as_me:$LINENO: checking for __int64" >&5 -echo $ECHO_N "checking for __int64... $ECHO_C" >&6 -if test "${ac_cv_type___int64+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((__int64 *) 0) - return 0; -if (sizeof (__int64)) - return 0; - ; - return 0; -} +cat >>confdefs.h <<\_ACEOF +#define ENABLE_RTL_FLAG_CHECKING 1 _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type___int64=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_type___int64=no fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type___int64" >&5 -echo "${ECHO_T}$ac_cv_type___int64" >&6 -if test $ac_cv_type___int64 = yes; then +if test x$ac_gc_checking != x ; then -cat >>confdefs.h <<_ACEOF -#define HAVE___INT64 1 +cat >>confdefs.h <<\_ACEOF +#define ENABLE_GC_CHECKING 1 _ACEOF -echo "$as_me:$LINENO: checking for __int64" >&5 -echo $ECHO_N "checking for __int64... $ECHO_C" >&6 -if test "${ac_cv_type___int64+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ +fi +if test x$ac_gc_always_collect != x ; then + +cat >>confdefs.h <<\_ACEOF +#define ENABLE_GC_ALWAYS_COLLECT 1 _ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((__int64 *) 0) - return 0; -if (sizeof (__int64)) - return 0; - ; - return 0; -} + +fi +if test x$ac_fold_checking != x ; then + +cat >>confdefs.h <<\_ACEOF +#define ENABLE_FOLD_CHECKING 1 _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type___int64=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_type___int64=no fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +valgrind_path_defines= +valgrind_command= + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi fi -echo "$as_me:$LINENO: result: $ac_cv_type___int64" >&5 -echo "${ECHO_T}$ac_cv_type___int64" >&6 +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep -echo "$as_me:$LINENO: checking size of __int64" >&5 -echo $ECHO_N "checking size of __int64... $ECHO_C" >&6 -if test "${ac_cv_sizeof___int64+set}" = set; then + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - if test "$ac_cv_type___int64" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (__int64))) >= 0)]; -test_array [0] = 0 +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default int main () { -static int test_array [1 - 2 * !(((long) (sizeof (__int64))) <= $ac_mid)]; -test_array [0] = 0 ; return 0; @@ -5818,193 +4108,61 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_hi=$ac_mid; break + ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` +ac_cv_header_stdc=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (__int64))) < 0)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (__int64))) >= $ac_mid)]; -test_array [0] = 0 +#include <string.h> - ; - return 0; -} _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` + ac_cv_header_stdc=no fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +rm -f conftest* -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (__int64))) <= $ac_mid)]; -test_array [0] = 0 +#include <stdlib.h> - ; - return 0; -} _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_header_stdc=no +fi +rm -f conftest* -ac_lo=`expr '(' $ac_mid ')' + 1` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof___int64=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (__int64), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (__int64), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } + : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ @@ -6012,36 +4170,28 @@ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (__int64)); } -unsigned long ulongval () { return (long) (sizeof (__int64)); } -#include <stdio.h> -#include <stdlib.h> +#include <ctype.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (__int64))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (__int64)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (__int64)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); } _ACEOF rm -f conftest$ac_exeext @@ -6055,278 +4205,57 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_sizeof___int64=`cat conftest.val` + : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (__int64), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (__int64), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } +ac_cv_header_stdc=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi -rm -f conftest.val -else - ac_cv_sizeof___int64=0 -fi fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof___int64" >&5 -echo "${ECHO_T}$ac_cv_sizeof___int64" >&6 -cat >>confdefs.h <<_ACEOF -#define SIZEOF___INT64 $ac_cv_sizeof___int64 -_ACEOF - - -fi - - -# --------------------- -# Warnings and checking -# --------------------- - -# Check $CC warning features (if it's GCC). -# We want to use -pedantic, but we don't want warnings about -# * 'long long' -# * variadic macros -# * overlong strings -# So, we only use -pedantic if we can disable those warnings. - -echo "$as_me:$LINENO: checking whether ${CC} accepts -Wno-long-long" >&5 -echo $ECHO_N "checking whether ${CC} accepts -Wno-long-long... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_w_no_long_long+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - save_CFLAGS="$CFLAGS" - CFLAGS="-Wno-long-long" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cc_w_no_long_long=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_prog_cc_w_no_long_long=no fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$save_CFLAGS" - -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cc_w_no_long_long" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_w_no_long_long" >&6 - -echo "$as_me:$LINENO: checking whether ${CC} accepts -Wno-variadic-macros" >&5 -echo $ECHO_N "checking whether ${CC} accepts -Wno-variadic-macros... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_w_no_variadic_macros+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - save_CFLAGS="$CFLAGS" - CFLAGS="-Wno-variadic-macros" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cc_w_no_variadic_macros=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +# On IRIX 5.3, sys/types and inttypes.h are conflicting. -ac_cv_prog_cc_w_no_variadic_macros=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$save_CFLAGS" -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cc_w_no_variadic_macros" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_w_no_variadic_macros" >&6 -echo "$as_me:$LINENO: checking whether ${CC} accepts -Wno-overlength-strings" >&5 -echo $ECHO_N "checking whether ${CC} accepts -Wno-overlength-strings... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_w_no_overlength_strings+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - save_CFLAGS="$CFLAGS" - CFLAGS="-Wno-overlength-strings" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cc_w_no_overlength_strings=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_prog_cc_w_no_overlength_strings=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$save_CFLAGS" -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cc_w_no_overlength_strings" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_w_no_overlength_strings" >&6 -strict1_warn= -if test $ac_cv_prog_cc_w_no_long_long = yes \ - && test $ac_cv_prog_cc_w_no_variadic_macros = yes \ - && test $ac_cv_prog_cc_w_no_overlength_strings = yes ; then - strict1_warn="-pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings" -fi -# Add -Wold-style-definition if it's accepted -echo "$as_me:$LINENO: checking whether ${CC} accepts -Wold-style-definition" >&5 -echo $ECHO_N "checking whether ${CC} accepts -Wold-style-definition... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_w_old_style_definition+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - save_CFLAGS="$CFLAGS" - CFLAGS="-Wold-style-definition" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cc_w_old_style_definition=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_prog_cc_w_old_style_definition=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$save_CFLAGS" - -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cc_w_old_style_definition" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_w_old_style_definition" >&6 -if test $ac_cv_prog_cc_w_old_style_definition = yes ; then - strict1_warn="${strict1_warn} -Wold-style-definition" -fi - -# Add -Wmissing-format-attribute if it's accepted -echo "$as_me:$LINENO: checking whether ${CC} accepts -Wmissing-format-attribute" >&5 -echo $ECHO_N "checking whether ${CC} accepts -Wmissing-format-attribute... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_w_missing_format_attribute+set}" = set; then +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - save_CFLAGS="$CFLAGS" - CFLAGS="-Wmissing-format-attribute" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 @@ -6350,265 +4279,26 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_prog_cc_w_missing_format_attribute=yes + eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_prog_cc_w_missing_format_attribute=no +eval "$as_ac_Header=no" fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$save_CFLAGS" - -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cc_w_missing_format_attribute" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_w_missing_format_attribute" >&6 -if test $ac_cv_prog_cc_w_missing_format_attribute = yes ; then - strict1_warn="${strict1_warn} -Wmissing-format-attribute" fi - -# Enable -Werror, period. -# Check whether --enable-werror_always or --disable-werror_always was given. -if test "${enable_werror_always+set}" = set; then - enableval="$enable_werror_always" - -else - enable_werror_always=no -fi; -if test x${enable_werror_always} = xyes ; then - strict1_warn="${strict1_warn} -Werror" - WERROR=-Werror -fi - - - -# Get C++ compatibility warning flag, if supported. -echo "$as_me:$LINENO: checking whether ${CC} accepts -Wc++-compat" >&5 -echo $ECHO_N "checking whether ${CC} accepts -Wc++-compat... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_w_cxx_compat+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - save_CFLAGS="$CFLAGS" - CFLAGS="-Wc++-compat" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cc_w_cxx_compat=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_prog_cc_w_cxx_compat=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$save_CFLAGS" - -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cc_w_cxx_compat" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_w_cxx_compat" >&6 -if test x${ac_cv_prog_cc_w_cxx_compat} = xyes; then - cxx_compat_warn="-Wc++-compat" -fi - - - -# If the native compiler is GCC, we can enable warnings even in stage1. -# That's useful for people building cross-compilers, or just running a -# quick `make'. -warn_cflags= -if test "x$GCC" = "xyes"; then - warn_cflags='$(GCC_WARN_CFLAGS)' -fi - - -# Enable -Werror in bootstrap stage2 and later. -is_release= -if test x"`cat $srcdir/DEV-PHASE`" != xexperimental; then - is_release=yes -fi -# Check whether --enable-werror or --disable-werror was given. -if test "${enable_werror+set}" = set; then - enableval="$enable_werror" - -else - if test x$is_release = x ; then - # Default to "yes" on development branches. - enable_werror=yes -else - # Default to "no" on release branches. - enable_werror=no -fi -fi; -if test x$enable_werror = xyes ; then - WERROR=-Werror fi - -# Enable expensive internal checks -# Check whether --enable-checking or --disable-checking was given. -if test "${enable_checking+set}" = set; then - enableval="$enable_checking" - ac_checking_flags="${enableval}" -else - -# Determine the default checks. -if test x$is_release = x ; then - ac_checking_flags=yes -else - ac_checking_flags=release -fi -fi; -ac_assert_checking=1 -ac_checking= -ac_fold_checking= -ac_gc_checking= -ac_gc_always_collect= -ac_rtl_checking= -ac_rtlflag_checking= -ac_runtime_checking=1 -ac_tree_checking= -ac_valgrind_checking= -IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="$IFS," -for check in $ac_checking_flags -do - case $check in - # these set all the flags to specific states - yes) ac_assert_checking=1 ; ac_checking=1 ; - ac_fold_checking= ; ac_gc_checking=1 ; - ac_gc_always_collect= ; ac_rtl_checking= ; - ac_rtlflag_checking=1 ; ac_runtime_checking=1 ; - ac_tree_checking=1 ; ac_valgrind_checking= ;; - no|none) ac_assert_checking= ; ac_checking= ; - ac_fold_checking= ; ac_gc_checking= ; - ac_gc_always_collect= ; ac_rtl_checking= ; - ac_rtlflag_checking= ; ac_runtime_checking= ; - ac_tree_checking= ; ac_valgrind_checking= ;; - all) ac_assert_checking=1 ; ac_checking=1 ; - ac_fold_checking=1 ; ac_gc_checking=1 ; - ac_gc_always_collect=1 ; ac_rtl_checking=1 ; - ac_rtlflag_checking=1 ; ac_runtime_checking=1 ; - ac_tree_checking=1 ; ac_valgrind_checking= ;; - release) ac_assert_checking=1 ; ac_checking= ; - ac_fold_checking= ; ac_gc_checking= ; - ac_gc_always_collect= ; ac_rtl_checking= ; - ac_rtlflag_checking= ; ac_runtime_checking=1 ; - ac_tree_checking= ; ac_valgrind_checking= ;; - # these enable particular checks - assert) ac_assert_checking=1 ;; - fold) ac_fold_checking=1 ;; - gc) ac_gc_checking=1 ;; - gcac) ac_gc_always_collect=1 ;; - misc) ac_checking=1 ;; - rtl) ac_rtl_checking=1 ;; - rtlflag) ac_rtlflag_checking=1 ;; - runtime) ac_runtime_checking=1 ;; - tree) ac_tree_checking=1 ;; - valgrind) ac_valgrind_checking=1 ;; - *) { { echo "$as_me:$LINENO: error: unknown check category $check" >&5 -echo "$as_me: error: unknown check category $check" >&2;} - { (exit 1); exit 1; }; } ;; - esac done -IFS="$ac_save_IFS" - -nocommon_flag="" -if test x$ac_checking != x ; then - -cat >>confdefs.h <<\_ACEOF -#define ENABLE_CHECKING 1 -_ACEOF - - nocommon_flag=-fno-common -fi - -if test x$ac_assert_checking != x ; then - -cat >>confdefs.h <<\_ACEOF -#define ENABLE_ASSERT_CHECKING 1 -_ACEOF - -fi - -if test x$ac_runtime_checking != x ; then - -cat >>confdefs.h <<\_ACEOF -#define ENABLE_RUNTIME_CHECKING 1 -_ACEOF - -fi -if test x$ac_tree_checking != x ; then - -cat >>confdefs.h <<\_ACEOF -#define ENABLE_TREE_CHECKING 1 -_ACEOF - - TREEBROWSER=tree-browser.o -fi - -if test x$ac_rtl_checking != x ; then - -cat >>confdefs.h <<\_ACEOF -#define ENABLE_RTL_CHECKING 1 -_ACEOF - -fi -if test x$ac_rtlflag_checking != x ; then - -cat >>confdefs.h <<\_ACEOF -#define ENABLE_RTL_FLAG_CHECKING 1 -_ACEOF - -fi -if test x$ac_gc_checking != x ; then - -cat >>confdefs.h <<\_ACEOF -#define ENABLE_GC_CHECKING 1 -_ACEOF -fi -if test x$ac_gc_always_collect != x ; then - -cat >>confdefs.h <<\_ACEOF -#define ENABLE_GC_ALWAYS_COLLECT 1 -_ACEOF - -fi -if test x$ac_fold_checking != x ; then - -cat >>confdefs.h <<\_ACEOF -#define ENABLE_FOLD_CHECKING 1 -_ACEOF - -fi -valgrind_path_defines= -valgrind_command= if test "${ac_cv_header_valgrind_h+set}" = set; then echo "$as_me:$LINENO: checking for valgrind.h" >&5 @@ -6755,7 +4445,7 @@ fi -if test x$ac_valgrind_checking != x ; then +if test x$ac_checking_valgrind != x ; then # It is certainly possible that there's valgrind but no valgrind.h. # GCC relies on making annotations so we must have both. echo "$as_me:$LINENO: checking for VALGRIND_DISCARD in <valgrind/memcheck.h>" >&5 @@ -6940,42 +4630,22 @@ fi -# Check whether --enable-mapped-location or --disable-mapped-location was given. -if test "${enable_mapped_location+set}" = set; then - enableval="$enable_mapped_location" - -else - enable_mapped_location=no -fi; - -if test "$enable_mapped_location" = yes ; then - -cat >>confdefs.h <<\_ACEOF -#define USE_MAPPED_LOCATION 1 -_ACEOF - -fi - # Enable code coverage collection # Check whether --enable-coverage or --disable-coverage was given. if test "${enable_coverage+set}" = set; then enableval="$enable_coverage" case "${enableval}" in - yes|noopt) - coverage_flags="-fprofile-arcs -ftest-coverage -frandom-seed=\$@ -O0" - ;; - opt) - coverage_flags="-fprofile-arcs -ftest-coverage -frandom-seed=\$@ -O2" - ;; - no) - # a.k.a. --disable-coverage - coverage_flags="" - ;; - *) - { { echo "$as_me:$LINENO: error: unknown coverage setting $enableval" >&5 +yes|noopt) + coverage_flags="-fprofile-arcs -ftest-coverage -frandom-seed=\$@ -O0" + ;; +opt) + coverage_flags="-fprofile-arcs -ftest-coverage -frandom-seed=\$@ -O2" + ;; +*) + { { echo "$as_me:$LINENO: error: unknown coverage setting $enableval" >&5 echo "$as_me: error: unknown coverage setting $enableval" >&2;} { (exit 1); exit 1; }; } - ;; + ;; esac else coverage_flags="" @@ -7028,37 +4698,6 @@ if test "${enable___cxa_atexit+set}" = set; then fi; -# Enable C extension for decimal float if target supports it. -# Check whether --enable-decimal-float or --disable-decimal-float was given. -if test "${enable_decimal_float+set}" = set; then - enableval="$enable_decimal_float" - - if test x$enablevar = xyes ; then - case $target in - powerpc*-*-linux* | i?86*-*-linux*) - enable_decimal_float=yes - ;; - *) - { echo "$as_me:$LINENO: WARNING: decimal float is not supported for this target" >&5 -echo "$as_me: WARNING: decimal float is not supported for this target" >&2;} - enable_decimal_float=no - ;; - esac - fi - -else - enable_decimal_float=no -fi; - - - -dfp=`if test $enable_decimal_float = yes; then echo 1; else echo 0; fi` - -cat >>confdefs.h <<_ACEOF -#define ENABLE_DECIMAL_FLOAT $dfp -_ACEOF - - # Enable threads # Pass with no value to take the default # Pass with a value to specify a thread package @@ -7069,23 +4708,8 @@ if test "${enable_threads+set}" = set; then else enable_threads='' fi; - -# Check whether --enable-tls or --disable-tls was given. -if test "${enable_tls+set}" = set; then - enableval="$enable_tls" - - case $enable_tls in - yes | no) ;; - *) { { echo "$as_me:$LINENO: error: '$enable_tls' is an invalid value for --enable-tls. -Valid choices are 'yes' and 'no'." >&5 -echo "$as_me: error: '$enable_tls' is an invalid value for --enable-tls. -Valid choices are 'yes' and 'no'." >&2;} - { (exit 1); exit 1; }; } ;; - esac - -else - enable_tls='' -fi; +# Save in case it gets overwritten in config.gcc +enable_threads_flag=$enable_threads # Check whether --enable-objc-gc or --disable-objc-gc was given. if test "${enable_objc_gc+set}" = set; then @@ -7132,13 +4756,6 @@ fi; -# Check whether --with-build-sysroot or --without-build-sysroot was given. -if test "${with_build_sysroot+set}" = set; then - withval="$with_build_sysroot" - -fi; - - # Check whether --with-sysroot or --without-sysroot was given. if test "${with_sysroot+set}" = set; then withval="$with_sysroot" @@ -7192,38 +4809,6 @@ else fi; -# Sanity check enable_languages in case someone does not run the toplevel -# configure # script. -# Check whether --enable-languages or --disable-languages was given. -if test "${enable_languages+set}" = set; then - enableval="$enable_languages" - case ,${enable_languages}, in - ,,|,yes,) - # go safe -- we cannot be much sure without the toplevel - # configure's - # analysis of which target libs are present and usable - enable_languages=c - ;; - *,all,*) - { { echo "$as_me:$LINENO: error: only the toplevel supports --enable-languages=all" >&5 -echo "$as_me: error: only the toplevel supports --enable-languages=all" >&2;} - { (exit 1); exit 1; }; } - ;; - *,c,*) - ;; - *) - enable_languages=c,${enable_languages} - ;; -esac -else - enable_languages=c -fi; - -# Used by documentation targets - - - - # ------------------------- # Checks for other programs # ------------------------- @@ -7299,7 +4884,7 @@ fi test -n "$AWK" && break done -# We need awk to create options.c and options.h. +# We need awk to run opts.sh (to create options.c and options.h). # Bail out if it's missing. case ${AWK} in "") { { echo "$as_me:$LINENO: error: can't build without awk, bailing out" >&5 @@ -7307,70 +4892,74 @@ echo "$as_me: error: can't build without awk, bailing out" >&2;} { (exit 1); exit 1; }; } ;; esac -echo "$as_me:$LINENO: checking whether ln -s works" >&5 -echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 -if test "${gcc_cv_prog_LN_S+set}" = set; then +echo "$as_me:$LINENO: checking whether ln works" >&5 +echo $ECHO_N "checking whether ln works... $ECHO_C" >&6 +if test "${gcc_cv_prog_LN+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else rm -f conftestdata_t echo >conftestdata_f -if ln -s conftestdata_f conftestdata_t 2>/dev/null +if ln conftestdata_f conftestdata_t 2>/dev/null then - gcc_cv_prog_LN_S="ln -s" + gcc_cv_prog_LN="ln" else - if ln conftestdata_f conftestdata_t 2>/dev/null + if ln -s conftestdata_f conftestdata_t 2>/dev/null then - gcc_cv_prog_LN_S=ln + gcc_cv_prog_LN="ln -s" else - if cp -p conftestdata_f conftestdata_t 2>/dev/null - then - gcc_cv_prog_LN_S="cp -p" - else - gcc_cv_prog_LN_S=cp - fi + gcc_cv_prog_LN=cp fi fi rm -f conftestdata_f conftestdata_t fi -LN_S="$gcc_cv_prog_LN_S" -if test "$gcc_cv_prog_LN_S" = "ln -s"; then +LN="$gcc_cv_prog_LN" +if test "$gcc_cv_prog_LN" = "ln"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else - if test "$gcc_cv_prog_LN_S" = "ln"; then - echo "$as_me:$LINENO: result: no, using ln" >&5 -echo "${ECHO_T}no, using ln" >&6 + if test "$gcc_cv_prog_LN" = "ln -s"; then + echo "$as_me:$LINENO: result: no, using ln -s" >&5 +echo "${ECHO_T}no, using ln -s" >&6 else - echo "$as_me:$LINENO: result: no, and neither does ln, so using $gcc_cv_prog_LN_S" >&5 -echo "${ECHO_T}no, and neither does ln, so using $gcc_cv_prog_LN_S" >&6 + echo "$as_me:$LINENO: result: no, and neither does ln -s, so using cp" >&5 +echo "${ECHO_T}no, and neither does ln -s, so using cp" >&6 fi fi -echo "$as_me:$LINENO: checking whether ln works" >&5 -echo $ECHO_N "checking whether ln works... $ECHO_C" >&6 -if test "${acx_cv_prog_LN+set}" = set; then +echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +if test "${gcc_cv_prog_LN_S+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else rm -f conftestdata_t echo >conftestdata_f -if ln conftestdata_f conftestdata_t 2>/dev/null +if ln -s conftestdata_f conftestdata_t 2>/dev/null then - acx_cv_prog_LN=ln + gcc_cv_prog_LN_S="ln -s" else - acx_cv_prog_LN=no + if ln conftestdata_f conftestdata_t 2>/dev/null + then + gcc_cv_prog_LN_S=ln + else + gcc_cv_prog_LN_S=cp + fi fi rm -f conftestdata_f conftestdata_t fi -if test $acx_cv_prog_LN = no; then - LN="$LN_S" - echo "$as_me:$LINENO: result: no, using $LN" >&5 -echo "${ECHO_T}no, using $LN" >&6 -else - LN="$acx_cv_prog_LN" +LN_S="$gcc_cv_prog_LN_S" +if test "$gcc_cv_prog_LN_S" = "ln -s"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 +else + if test "$gcc_cv_prog_LN_S" = "ln"; then + echo "$as_me:$LINENO: result: no, using ln" >&5 +echo "${ECHO_T}no, using ln" >&6 + else + echo "$as_me:$LINENO: result: no, and neither does ln, so using cp" >&5 +echo "${ECHO_T}no, and neither does ln, so using cp" >&6 + fi fi if test -n "$ac_tool_prefix"; then @@ -7453,19 +5042,6 @@ else RANLIB="$ac_cv_prog_RANLIB" fi -case "${host}" in -*-*-darwin*) - # By default, the Darwin ranlib will not treat common symbols as - # definitions when building the archive table of contents. Other - # ranlibs do that; pass an option to the Darwin ranlib that makes - # it behave similarly. - ranlib_flags="-c" - ;; -*) - ranlib_flags="" -esac - - # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: @@ -7600,14 +5176,16 @@ echo "${ECHO_T}no" >&6 fi -MISSING="${CONFIG_SHELL-/bin/sh} $srcdir/../missing" - -# See if makeinfo has been installed and is modern enough -# that we can use it. - -ac_executable_extensions="$build_exeext" - -# Extract the first word of "makeinfo", so it can be a program name with args. +# Do we have a single-tree copy of texinfo? +if test -f $srcdir/../texinfo/Makefile.in; then + MAKEINFO='$(objdir)/../texinfo/makeinfo/makeinfo' + gcc_cv_prog_makeinfo_modern=yes + echo "$as_me:$LINENO: result: Using makeinfo from the unified source tree." >&5 +echo "${ECHO_T}Using makeinfo from the unified source tree." >&6 +else + # See if makeinfo has been installed and is modern enough + # that we can use it. + # Extract the first word of "makeinfo", so it can be a program name with args. set dummy makeinfo; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 @@ -7651,10 +5229,10 @@ if test "${gcc_cv_prog_makeinfo_modern+set}" = set; then else ac_prog_version=`$MAKEINFO --version 2>&1 | sed -n 's/^.*GNU texinfo.* \([0-9][0-9.]*\).*$/\1/p'` - echo "configure:7654: version of makeinfo is $ac_prog_version" >&5 + echo "configure:5232: version of makeinfo is $ac_prog_version" >&5 case $ac_prog_version in '') gcc_cv_prog_makeinfo_modern=no;; - 4.[4-9]*) + 4.[2-9]*) gcc_cv_prog_makeinfo_modern=yes;; *) gcc_cv_prog_makeinfo_modern=no;; esac @@ -7666,8 +5244,9 @@ else gcc_cv_prog_makeinfo_modern=no fi +fi + if test $gcc_cv_prog_makeinfo_modern = no; then - MAKEINFO="$MISSING makeinfo" { echo "$as_me:$LINENO: WARNING: *** Makeinfo is missing or too old. *** Info documentation will not be built." >&5 @@ -7679,7 +5258,6 @@ else BUILD_INFO=info fi - # Is pod2man recent enough to regenerate manpages? echo "$as_me:$LINENO: checking for recent Pod::Man" >&5 echo $ECHO_N "checking for recent Pod::Man... $ECHO_C" >&6 @@ -7693,12 +5271,12 @@ echo "${ECHO_T}no" >&6 GENERATED_MANPAGES= fi - # How about lex? -for ac_prog in flex -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 +if test -f $srcdir/../flex/skel.c; then + FLEX='$(objdir)/../flex/flex' +else + # Extract the first word of "flex", so it can be a program name with args. +set dummy flex; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_FLEX+set}" = set; then @@ -7714,13 +5292,14 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_FLEX="$ac_prog" + ac_cv_prog_FLEX="flex" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done + test -z "$ac_cv_prog_FLEX" && ac_cv_prog_FLEX="${CONFIG_SHELL-/bin/sh} ${srcdir}/../missing flex" fi fi FLEX=$ac_cv_prog_FLEX @@ -7732,16 +5311,15 @@ else echo "${ECHO_T}no" >&6 fi - test -n "$FLEX" && break -done -test -n "$FLEX" || FLEX="$MISSING flex" - +fi # Bison? -for ac_prog in bison -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 +# The -L switch is so bison can find its skeleton file. +if test -f $srcdir/../bison/bison.simple; then + BISON='$(objdir)/../bison/bison -L $(srcdir)/../bison/' +else + # Extract the first word of "bison", so it can be a program name with args. +set dummy bison; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_BISON+set}" = set; then @@ -7757,13 +5335,14 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_BISON="$ac_prog" + ac_cv_prog_BISON="bison" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done + test -z "$ac_cv_prog_BISON" && ac_cv_prog_BISON="${CONFIG_SHELL-/bin/sh} ${srcdir}/../missing bison" fi fi BISON=$ac_cv_prog_BISON @@ -7775,101 +5354,8 @@ else echo "${ECHO_T}no" >&6 fi - test -n "$BISON" && break -done -test -n "$BISON" || BISON="$MISSING bison" - - -# Binutils are not build modules, unlike bison/flex/makeinfo. So we -# check for build == host before using them. - -# NM -if test x${build} = x${host} && test -f $srcdir/../binutils/nm.c \ - && test -d ../binutils ; then - NM='$(objdir)/../binutils/nm-new' -else - # Extract the first word of "nm", so it can be a program name with args. -set dummy nm; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_NM+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$NM"; then - ac_cv_prog_NM="$NM" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_NM="nm" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - - test -z "$ac_cv_prog_NM" && ac_cv_prog_NM="${CONFIG_SHELL-/bin/sh} ${srcdir}/../missing nm" -fi -fi -NM=$ac_cv_prog_NM -if test -n "$NM"; then - echo "$as_me:$LINENO: result: $NM" >&5 -echo "${ECHO_T}$NM" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - -fi - -# AR -if test x${build} = x${host} && test -f $srcdir/../binutils/ar.c \ - && test -d ../binutils ; then - AR='$(objdir)/../binutils/ar' -else - # Extract the first word of "ar", so it can be a program name with args. -set dummy ar; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_AR+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="ar" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - - test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="${CONFIG_SHELL-/bin/sh} ${srcdir}/../missing ar" -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - echo "$as_me:$LINENO: result: $AR" >&5 -echo "${ECHO_T}$AR" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - fi - # -------------------- # Checks for C headers # -------------------- @@ -8175,6 +5661,67 @@ _ACEOF fi +echo "$as_me:$LINENO: checking for working stdbool.h" >&5 +echo $ECHO_N "checking for working stdbool.h... $ECHO_C" >&6 +if test "${ac_cv_header_stdbool_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdbool.h> +int +main () +{ +bool foo = false; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdbool_h=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdbool_h=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdbool_h" >&5 +echo "${ECHO_T}$ac_cv_header_stdbool_h" >&6 +if test $ac_cv_header_stdbool_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_STDBOOL_H 1 +_ACEOF + +fi + echo "$as_me:$LINENO: checking whether string.h and strings.h may both be included" >&5 echo $ECHO_N "checking whether string.h and strings.h may both be included... $ECHO_C" >&6 if test "${gcc_cv_header_string+set}" = set; then @@ -8329,8 +5876,7 @@ fi - -for ac_header in limits.h stddef.h string.h strings.h stdlib.h time.h iconv.h \ +for ac_header in limits.h stddef.h string.h strings.h stdlib.h time.h \ fcntl.h unistd.h sys/file.h sys/time.h sys/mman.h \ sys/resource.h sys/param.h sys/times.h sys/stat.h \ direct.h malloc.h langinfo.h ldfcn.h locale.h wchar.h @@ -8596,7 +6142,8 @@ echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6 if test "${ac_cv_c_bigendian+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - # See if sys/param.h defines the BYTE_ORDER macro. + ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -8605,14 +6152,13 @@ cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <sys/types.h> #include <sys/param.h> - int main () { + #if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN bogus endian macros #endif - ; return 0; } @@ -8648,14 +6194,13 @@ cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <sys/types.h> #include <sys/param.h> - int main () { + #if BYTE_ORDER != BIG_ENDIAN not big endian #endif - ; return 0; } @@ -8694,69 +6239,11 @@ else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -# It does not; compile a test program. -if test "$cross_compiling" = yes; then - # try to guess the endianness by grepping values into an object file - ac_cv_c_bigendian=unknown - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; -short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; -void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } -short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; -short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; -void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } -int -main () -{ - _ascii (); _ebcdic (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then - ac_cv_c_bigendian=yes -fi -if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then - if test "$ac_cv_c_bigendian" = unknown; then - ac_cv_c_bigendian=no - else - # finding both strings is unlikely to happen, but who knows? - ac_cv_c_bigendian=unknown - fi -fi -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +if test $ac_cv_c_bigendian = unknown; then +if test "$cross_compiling" = yes; then + echo $ac_n "cross-compiling... " 2>&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ @@ -8764,9 +6251,7 @@ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -int -main () -{ +main () { /* Are we little or big endian? From Harbison&Steele. */ union { @@ -8800,26 +6285,67 @@ fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 echo "${ECHO_T}$ac_cv_c_bigendian" >&6 -case $ac_cv_c_bigendian in - yes) +if test $ac_cv_c_bigendian = unknown; then +echo "$as_me:$LINENO: checking to probe for byte ordering" >&5 +echo $ECHO_N "checking to probe for byte ordering... $ECHO_C" >&6 + +cat >conftest.c <<EOF +short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; +short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; +void _ascii() { char* s = (char*) ascii_mm; s = (char*) ascii_ii; } +short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; +short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; +void _ebcdic() { char* s = (char*) ebcdic_mm; s = (char*) ebcdic_ii; } +int main() { _ascii (); _ebcdic (); return 0; } +EOF + if test -f conftest.c ; then + if ${CC-cc} ${CFLAGS} conftest.c -o conftest.o && test -f conftest.o ; then + if test `grep -l BIGenDianSyS conftest.o` ; then + echo $ac_n ' big endian probe OK, ' 1>&6 + ac_cv_c_bigendian=yes + fi + if test `grep -l LiTTleEnDian conftest.o` ; then + echo $ac_n ' little endian probe OK, ' 1>&6 + if test $ac_cv_c_bigendian = yes ; then + ac_cv_c_bigendian=unknown; + else + ac_cv_c_bigendian=no + fi + fi + echo $ac_n 'guessing bigendian ... ' >&6 + fi + fi +echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +echo "${ECHO_T}$ac_cv_c_bigendian" >&6 +fi +if test $ac_cv_c_bigendian = yes; then cat >>confdefs.h <<\_ACEOF #define WORDS_BIGENDIAN 1 _ACEOF - ;; - no) - ;; - *) - { { echo "$as_me:$LINENO: error: unknown endianness -presetting ac_cv_c_bigendian=no (or yes) will help" >&5 -echo "$as_me: error: unknown endianness -presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} - { (exit 1); exit 1; }; } ;; -esac + + +cat >>confdefs.h <<\_ACEOF +#define HOST_WORDS_BIG_ENDIAN 1 +_ACEOF + + BYTEORDER=4321 +else + BYTEORDER=1234 +fi + +cat >>confdefs.h <<_ACEOF +#define BYTEORDER $BYTEORDER +_ACEOF + +if test $ac_cv_c_bigendian = unknown; then + { { echo "$as_me:$LINENO: error: unknown endianess - sorry" >&5 +echo "$as_me: error: unknown endianess - sorry" >&2;} + { (exit please pre-set ac_cv_c_bigendian); exit please pre-set ac_cv_c_bigendian; }; } +fi # -------- @@ -8837,6 +6363,13 @@ vax-*-*) stage1_cflags="-J" fi ;; +powerpc-*-darwin*) + # The spiffy cpp-precomp chokes on some legitimate constructs in GCC + # sources; use -no-cpp-precomp to get to GNU cpp. + # Apple's GCC has bugs in designated initializer handling, so disable + # that too. + stage1_cflags="-no-cpp-precomp -DHAVE_DESIGNATED_INITIALIZERS=0" + ;; esac @@ -9276,21 +6809,11 @@ fi - - - - - - - - - - - -for ac_func in times clock kill getrlimit setrlimit atoll atoq \ - sysconf strsignal getrusage nl_langinfo scandir alphasort \ - gettimeofday mbstowcs wcswidth mmap mincore setlocale \ - clearerr_unlocked feof_unlocked ferror_unlocked fflush_unlocked fgetc_unlocked fgets_unlocked fileno_unlocked fprintf_unlocked fputc_unlocked fputs_unlocked fread_unlocked fwrite_unlocked getchar_unlocked getc_unlocked putchar_unlocked putc_unlocked +for ac_func in times clock dup2 kill getrlimit setrlimit atoll atoq \ + sysconf strsignal putc_unlocked fputc_unlocked fputs_unlocked \ + fwrite_unlocked fprintf_unlocked getrusage nl_langinfo \ + scandir alphasort gettimeofday mbstowcs wcswidth mmap mincore \ + setlocale do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -9659,59 +7182,13 @@ else fi - -echo "$as_me:$LINENO: checking for sys/mman.h" >&5 -echo $ECHO_N "checking for sys/mman.h... $ECHO_C" >&6 -if test "${ac_cv_header_sys_mman_h+set}" = set; then +echo "$as_me:$LINENO: checking whether the printf functions support %p" >&5 +echo $ECHO_N "checking whether the printf functions support %p... $ECHO_C" >&6 +if test "${gcc_cv_func_printf_ptr+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <sys/mman.h> -_ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - ac_cpp_err=$ac_cpp_err$ac_c_werror_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then - ac_cv_header_sys_mman_h=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_header_sys_mman_h=no -fi -rm -f conftest.err conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_header_sys_mman_h" >&5 -echo "${ECHO_T}$ac_cv_header_sys_mman_h" >&6 -if test $ac_cv_header_sys_mman_h = yes; then - gcc_header_sys_mman_h=yes -else - gcc_header_sys_mman_h=no -fi - -echo "$as_me:$LINENO: checking for mmap" >&5 -echo $ECHO_N "checking for mmap... $ECHO_C" >&6 -if test "${ac_cv_func_mmap+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 + if test "$cross_compiling" = yes; then + gcc_cv_func_printf_ptr=no else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ @@ -9719,93 +7196,53 @@ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -/* Define mmap to an innocuous variant, in case <limits.h> declares mmap. - For example, HP-UX 11i <limits.h> declares gettimeofday. */ -#define mmap innocuous_mmap - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char mmap (); below. - Prefer <limits.h> to <assert.h> if __STDC__ is defined, since - <limits.h> exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include <limits.h> -#else -# include <assert.h> -#endif - -#undef mmap - -/* Override any gcc2 internal prototype to avoid an error. */ -#ifdef __cplusplus -extern "C" -{ -#endif -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char mmap (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_mmap) || defined (__stub___mmap) -choke me -#else -char (*f) () = mmap; -#endif -#ifdef __cplusplus -} -#endif +#include <stdio.h> -int -main () +int main() { -return f != mmap; - ; - return 0; + char buf[64]; + char *p = buf, *q = NULL; + sprintf(buf, "%p", p); + sscanf(buf, "%p", &q); + return (p != q); } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext +rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 + (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_func_mmap=yes + gcc_cv_func_printf_ptr=yes else - echo "$as_me: failed program was:" >&5 + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_func_mmap=no +( exit $ac_status ) +gcc_cv_func_printf_ptr=no fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_func_mmap" >&5 -echo "${ECHO_T}$ac_cv_func_mmap" >&6 -if test $ac_cv_func_mmap = yes; then - gcc_func_mmap=yes -else - gcc_func_mmap=no +rm -f core core.* *.core fi +echo "$as_me:$LINENO: result: $gcc_cv_func_printf_ptr" >&5 +echo "${ECHO_T}$gcc_cv_func_printf_ptr" >&6 +if test $gcc_cv_func_printf_ptr = yes ; then -if test "$gcc_header_sys_mman_h" != yes \ - || test "$gcc_func_mmap" != yes; then +cat >>confdefs.h <<\_ACEOF +#define HAVE_PRINTF_PTR 1 +_ACEOF + +fi + +if test $ac_cv_header_sys_mman_h != yes \ + || test $ac_cv_func_mmap != yes; then gcc_cv_func_mmap_file=no gcc_cv_func_mmap_dev_zero=no gcc_cv_func_mmap_anon=no @@ -10429,576 +7866,73 @@ fi - if test "X$prefix" = "XNONE"; then - acl_final_prefix="$ac_default_prefix" - else - acl_final_prefix="$prefix" - fi - if test "X$exec_prefix" = "XNONE"; then - acl_final_exec_prefix='${prefix}' - else - acl_final_exec_prefix="$exec_prefix" - fi - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" - prefix="$acl_save_prefix" - - -# Check whether --with-gnu-ld or --without-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then - withval="$with_gnu_ld" - test "$withval" = no || with_gnu_ld=yes -else - with_gnu_ld=no -fi; -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - echo "$as_me:$LINENO: checking for ld used by GCC" >&5 -echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6 - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | [A-Za-z]:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the path of ld - ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` - while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - echo "$as_me:$LINENO: checking for GNU ld" >&5 -echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 -else - echo "$as_me:$LINENO: checking for non-GNU ld" >&5 -echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 -fi -if test "${acl_cv_path_LD+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -z "$LD"; then - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - acl_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some GNU ld's only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - if "$acl_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then - test "$with_gnu_ld" != no && break - else - test "$with_gnu_ld" != yes && break - fi - fi - done - IFS="$ac_save_ifs" -else - acl_cv_path_LD="$LD" # Let the user override the test with a path. -fi -fi - -LD="$acl_cv_path_LD" -if test -n "$LD"; then - echo "$as_me:$LINENO: result: $LD" >&5 -echo "${ECHO_T}$LD" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi -test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 -echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} - { (exit 1); exit 1; }; } -echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 -echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 -if test "${acl_cv_prog_gnu_ld+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - # I'd rather use --version here, but apparently some GNU ld's only accept -v. -if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then - acl_cv_prog_gnu_ld=yes -else - acl_cv_prog_gnu_ld=no -fi -fi -echo "$as_me:$LINENO: result: $acl_cv_prog_gnu_ld" >&5 -echo "${ECHO_T}$acl_cv_prog_gnu_ld" >&6 -with_gnu_ld=$acl_cv_prog_gnu_ld - - - - echo "$as_me:$LINENO: checking for shared library run path origin" >&5 -echo $ECHO_N "checking for shared library run path origin... $ECHO_C" >&6 -if test "${acl_cv_rpath+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - - CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ - ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh - . ./conftest.sh - rm -f ./conftest.sh - acl_cv_rpath=done - -fi -echo "$as_me:$LINENO: result: $acl_cv_rpath" >&5 -echo "${ECHO_T}$acl_cv_rpath" >&6 - wl="$acl_cv_wl" - libext="$acl_cv_libext" - shlibext="$acl_cv_shlibext" - hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" - hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" - hardcode_direct="$acl_cv_hardcode_direct" - hardcode_minus_L="$acl_cv_hardcode_minus_L" - # Check whether --enable-rpath or --disable-rpath was given. -if test "${enable_rpath+set}" = set; then - enableval="$enable_rpath" - : -else - enable_rpath=yes -fi; - - - - - - - - use_additional=yes - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" + am_cv_lib_iconv_ldpath= # Check whether --with-libiconv-prefix or --without-libiconv-prefix was given. if test "${with_libiconv_prefix+set}" = set; then withval="$with_libiconv_prefix" - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - else - additional_includedir="$withval/include" - additional_libdir="$withval/lib" - fi - fi - -fi; - LIBICONV= - LTLIBICONV= - INCICONV= - rpathdirs= - ltrpathdirs= - names_already_handled= - names_next_round='iconv ' - while test -n "$names_next_round"; do - names_this_round="$names_next_round" - names_next_round= - for name in $names_this_round; do - already_handled= - for n in $names_already_handled; do - if test "$n" = "$name"; then - already_handled=yes - break - fi - done - if test -z "$already_handled"; then - names_already_handled="$names_already_handled $name" - uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` - eval value=\"\$HAVE_LIB$uppername\" - if test -n "$value"; then - if test "$value" = yes; then - eval value=\"\$LIB$uppername\" - test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value" - eval value=\"\$LTLIB$uppername\" - test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value" - else - : - fi - else - found_dir= - found_la= - found_so= - found_a= - if test $use_additional = yes; then - if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then - found_dir="$additional_libdir" - found_so="$additional_libdir/lib$name.$shlibext" - if test -f "$additional_libdir/lib$name.la"; then - found_la="$additional_libdir/lib$name.la" - fi - else - if test -f "$additional_libdir/lib$name.$libext"; then - found_dir="$additional_libdir" - found_a="$additional_libdir/lib$name.$libext" - if test -f "$additional_libdir/lib$name.la"; then - found_la="$additional_libdir/lib$name.la" - fi - fi - fi - fi - if test "X$found_dir" = "X"; then - for x in $LDFLAGS $LTLIBICONV; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - case "$x" in - -L*) - dir=`echo "X$x" | sed -e 's/^X-L//'` - if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then - found_dir="$dir" - found_so="$dir/lib$name.$shlibext" - if test -f "$dir/lib$name.la"; then - found_la="$dir/lib$name.la" - fi - else - if test -f "$dir/lib$name.$libext"; then - found_dir="$dir" - found_a="$dir/lib$name.$libext" - if test -f "$dir/lib$name.la"; then - found_la="$dir/lib$name.la" - fi - fi - fi - ;; - esac - if test "X$found_dir" != "X"; then - break - fi - done - fi - if test "X$found_dir" != "X"; then - LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name" - if test "X$found_so" != "X"; then - if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then - LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" - else - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $found_dir" - fi - if test "$hardcode_direct" = yes; then - LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" - else - if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then - LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $found_dir" - fi - else - haveit= - for x in $LDFLAGS $LIBICONV; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir" - fi - if test "$hardcode_minus_L" != no; then - LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" - else - LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" - fi - fi - fi - fi - else - if test "X$found_a" != "X"; then - LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a" - else - LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name" - fi - fi - additional_includedir= - case "$found_dir" in - */lib | */lib/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` - additional_includedir="$basedir/include" - ;; - esac - if test "X$additional_includedir" != "X"; then - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux*) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - for x in $CPPFLAGS $INCICONV; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir" - fi - fi - fi - fi - fi - if test -n "$found_la"; then - save_libdir="$libdir" - case "$found_la" in - */* | *\\*) . "$found_la" ;; - *) . "./$found_la" ;; - esac - libdir="$save_libdir" - for dep in $dependency_libs; do - case "$dep" in - -L*) - additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` - if test "X$additional_libdir" != "X/usr/lib"; then - haveit= - if test "X$additional_libdir" = "X/usr/local/lib"; then - if test -n "$GCC"; then - case $host_os in - linux*) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - haveit= - for x in $LDFLAGS $LIBICONV; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir" - fi - fi - haveit= - for x in $LDFLAGS $LTLIBICONV; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir" - fi - fi - fi - fi - ;; - -R*) - dir=`echo "X$dep" | sed -e 's/^X-R//'` - if test "$enable_rpath" != no; then - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $dir" - fi - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $dir" - fi - fi - ;; - -l*) - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` - ;; - *.la) - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` - ;; - *) - LIBICONV="${LIBICONV}${LIBICONV:+ }$dep" - LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep" - ;; - esac - done - fi - else - LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" - LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name" - fi - fi - fi + for dir in `echo "$withval" | tr : ' '`; do + if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi + if test -d $dir/lib; then am_cv_lib_iconv_ldpath="-L$dir/lib"; fi done - done - if test "X$rpathdirs" != "X"; then - if test -n "$hardcode_libdir_separator"; then - alldirs= - for found_dir in $rpathdirs; do - alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" - done - acl_save_libdir="$libdir" - libdir="$alldirs" - eval flag=\"$hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" - else - for found_dir in $rpathdirs; do - acl_save_libdir="$libdir" - libdir="$found_dir" - eval flag=\"$hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" - done - fi - fi - if test "X$ltrpathdirs" != "X"; then - for found_dir in $ltrpathdirs; do - LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir" - done - fi - - - - - +fi; - am_save_CPPFLAGS="$CPPFLAGS" - for element in $INCICONV; do - haveit= - for x in $CPPFLAGS; do +for ac_header in iconv.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF - if test "X$x" = "X$element"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" - fi - done +fi +done echo "$as_me:$LINENO: checking for iconv" >&5 @@ -11059,7 +7993,7 @@ rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" - LIBS="$LIBS $LIBICONV" + LIBS="$LIBS $am_cv_libiconv_ldpath -liconv" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -11121,21 +8055,6 @@ cat >>confdefs.h <<\_ACEOF #define HAVE_ICONV 1 _ACEOF - fi - if test "$am_cv_lib_iconv" = yes; then - echo "$as_me:$LINENO: checking how to link with libiconv" >&5 -echo $ECHO_N "checking how to link with libiconv... $ECHO_C" >&6 - echo "$as_me:$LINENO: result: $LIBICONV" >&5 -echo "${ECHO_T}$LIBICONV" >&6 - else - CPPFLAGS="$am_save_CPPFLAGS" - LIBICONV= - LTLIBICONV= - fi - - - - if test "$am_cv_func_iconv" = yes; then echo "$as_me:$LINENO: checking for iconv declaration" >&5 echo $ECHO_N "checking for iconv declaration... $ECHO_C" >&6 if test "${am_cv_proto_iconv+set}" = set; then @@ -11213,6 +8132,11 @@ cat >>confdefs.h <<_ACEOF _ACEOF fi + LIBICONV= + if test "$am_cv_lib_iconv" = yes; then + LIBICONV="$am_cv_lib_iconv_ldpath -liconv" + fi + # Until we have in-tree GNU iconv: LIBICONV_DEP= @@ -11282,119 +8206,15 @@ _ACEOF fi - - echo "$as_me:$LINENO: checking for nl_langinfo and CODESET" >&5 -echo $ECHO_N "checking for nl_langinfo and CODESET... $ECHO_C" >&6 -if test "${am_cv_langinfo_codeset+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <langinfo.h> -int -main () -{ -char* cs = nl_langinfo(CODESET); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - am_cv_langinfo_codeset=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -am_cv_langinfo_codeset=no -fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi -echo "$as_me:$LINENO: result: $am_cv_langinfo_codeset" >&5 -echo "${ECHO_T}$am_cv_langinfo_codeset" >&6 - if test $am_cv_langinfo_codeset = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LANGINFO_CODESET 1 -_ACEOF - - fi - - # We will need to find libiberty.h and ansidecl.h saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -I${srcdir} -I${srcdir}/../include" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -for ac_func in getenv atol asprintf sbrk abort atof getcwd getwd \ - strsignal strstr strverscmp \ - errno snprintf vsnprintf vasprintf malloc realloc calloc \ - free basename getopt clock getpagesize clearerr_unlocked feof_unlocked ferror_unlocked fflush_unlocked fgetc_unlocked fgets_unlocked fileno_unlocked fprintf_unlocked fputc_unlocked fputs_unlocked fread_unlocked fwrite_unlocked getchar_unlocked getc_unlocked putchar_unlocked putc_unlocked +for ac_func in getenv atol sbrk abort atof getcwd getwd \ + strsignal putc_unlocked fputs_unlocked fwrite_unlocked \ + fprintf_unlocked strstr errno snprintf vasprintf \ + malloc realloc calloc free basename getopt clock do - ac_tr_decl=`echo "HAVE_DECL_$ac_func" | $as_tr_cpp` + ac_tr_decl=HAVE_DECL_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` echo "$as_me:$LINENO: checking whether $ac_func is declared" >&5 echo $ECHO_N "checking whether $ac_func is declared... $ECHO_C" >&6 if eval "test \"\${gcc_cv_have_decl_$ac_func+set}\" = set"; then @@ -11469,14 +8289,108 @@ _ACEOF fi done +if test x = y ; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_GETENV 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_ATOL 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_SBRK 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_ABORT 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_ATOF 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_GETCWD 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_GETWD 1 +_ACEOF + \ + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_STRSIGNAL 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_PUTC_UNLOCKED 1 +_ACEOF +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_FPUTS_UNLOCKED 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_FWRITE_UNLOCKED 1 +_ACEOF + \ + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_FPRINTF_UNLOCKED 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_STRSTR 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_ERRNO 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_SNPRINTF 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_VASPRINTF 1 +_ACEOF + \ + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_MALLOC 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_REALLOC 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_CALLOC 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_FREE 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_BASENAME 1 +_ACEOF +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_GETOPT 1 +_ACEOF +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_CLOCK 1 +_ACEOF +fi for ac_func in getrlimit setrlimit getrusage do - ac_tr_decl=`echo "HAVE_DECL_$ac_func" | $as_tr_cpp` + ac_tr_decl=HAVE_DECL_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` echo "$as_me:$LINENO: checking whether $ac_func is declared" >&5 echo $ECHO_N "checking whether $ac_func is declared... $ECHO_C" >&6 if eval "test \"\${gcc_cv_have_decl_$ac_func+set}\" = set"; then @@ -11555,6 +8469,20 @@ _ACEOF fi done +if test x = y ; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_GETRLIMIT 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_SETRLIMIT 1 +_ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_GETRUSAGE 1 +_ACEOF +fi cat >conftest.$ac_ext <<_ACEOF @@ -11613,14 +8541,9 @@ _ACEOF fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# On AIX 5.2, <ldfcn.h> conflicts with <fcntl.h>, as both define incompatible -# FREAD and FWRITE macros. Fortunately, for GCC's single usage of ldgetname -# in collect2.c, <fcntl.h> isn't visible, but the configure test below needs -# to undef these macros to get the correct value for HAVE_DECL_LDGETNAME. - for ac_func in ldgetname do - ac_tr_decl=`echo "HAVE_DECL_$ac_func" | $as_tr_cpp` + ac_tr_decl=HAVE_DECL_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` echo "$as_me:$LINENO: checking whether $ac_func is declared" >&5 echo $ECHO_N "checking whether $ac_func is declared... $ECHO_C" >&6 if eval "test \"\${gcc_cv_have_decl_$ac_func+set}\" = set"; then @@ -11638,8 +8561,6 @@ cat >>conftest.$ac_ext <<_ACEOF #include "ansidecl.h" #include "system.h" #ifdef HAVE_LDFCN_H -#undef FREAD -#undef FWRITE #include <ldfcn.h> #endif @@ -11701,12 +8622,17 @@ _ACEOF fi done +if test x = y ; then +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_LDGETNAME 1 +_ACEOF +fi for ac_func in times do - ac_tr_decl=`echo "HAVE_DECL_$ac_func" | $as_tr_cpp` + ac_tr_decl=HAVE_DECL_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` echo "$as_me:$LINENO: checking whether $ac_func is declared" >&5 echo $ECHO_N "checking whether $ac_func is declared... $ECHO_C" >&6 if eval "test \"\${gcc_cv_have_decl_$ac_func+set}\" = set"; then @@ -11785,37 +8711,38 @@ _ACEOF fi done +if test x = y ; then +cat >>confdefs.h <<\_ACEOF +#define HAVE_DECL_TIMES 1 +_ACEOF +fi -for ac_func in sigaltstack -do - ac_tr_decl=`echo "HAVE_DECL_$ac_func" | $as_tr_cpp` -echo "$as_me:$LINENO: checking whether $ac_func is declared" >&5 -echo $ECHO_N "checking whether $ac_func is declared... $ECHO_C" >&6 -if eval "test \"\${gcc_cv_have_decl_$ac_func+set}\" = set"; then +# More time-related stuff. +echo "$as_me:$LINENO: checking for struct tms" >&5 +echo $ECHO_N "checking for struct tms... $ECHO_C" >&6 +if test "${ac_cv_struct_tms+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#undef $ac_tr_decl -#define $ac_tr_decl 1 #include "ansidecl.h" #include "system.h" -#include <signal.h> - +#ifdef HAVE_SYS_TIMES_H +#include <sys/times.h> +#endif int main () { -#ifndef $ac_func -char *(*pfn) = (char *(*)) $ac_func ; -#endif +struct tms tms; ; return 0; } @@ -11842,37 +8769,30 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - eval "gcc_cv_have_decl_$ac_func=yes" + ac_cv_struct_tms=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -eval "gcc_cv_have_decl_$ac_func=no" +ac_cv_struct_tms=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi +echo "$as_me:$LINENO: result: $ac_cv_struct_tms" >&5 +echo "${ECHO_T}$ac_cv_struct_tms" >&6 +if test $ac_cv_struct_tms = yes; then -if eval "test \"`echo '$gcc_cv_have_decl_'$ac_func`\" = yes"; then - echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6 ; cat >>confdefs.h <<_ACEOF -#define $ac_tr_decl 1 -_ACEOF - -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 ; cat >>confdefs.h <<_ACEOF -#define $ac_tr_decl 0 +cat >>confdefs.h <<\_ACEOF +#define HAVE_STRUCT_TMS 1 _ACEOF fi -done - - -# More time-related stuff. -echo "$as_me:$LINENO: checking for struct tms" >&5 -echo $ECHO_N "checking for struct tms... $ECHO_C" >&6 -if test "${ac_cv_struct_tms+set}" = set; then +# use gcc_cv_* here because this doesn't match the behavior of AC_CHECK_TYPE. +# revisit after autoconf 2.50. +echo "$as_me:$LINENO: checking for clock_t" >&5 +echo $ECHO_N "checking for clock_t... $ECHO_C" >&6 +if test "${gcc_cv_type_clock_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else @@ -11885,14 +8805,11 @@ cat >>conftest.$ac_ext <<_ACEOF #include "ansidecl.h" #include "system.h" -#ifdef HAVE_SYS_TIMES_H -#include <sys/times.h> -#endif int main () { -struct tms tms; +clock_t x; ; return 0; } @@ -11919,34 +8836,31 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_struct_tms=yes + gcc_cv_type_clock_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_struct_tms=no +gcc_cv_type_clock_t=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_struct_tms" >&5 -echo "${ECHO_T}$ac_cv_struct_tms" >&6 -if test $ac_cv_struct_tms = yes; then +echo "$as_me:$LINENO: result: $gcc_cv_type_clock_t" >&5 +echo "${ECHO_T}$gcc_cv_type_clock_t" >&6 +if test $gcc_cv_type_clock_t = yes; then cat >>confdefs.h <<\_ACEOF -#define HAVE_STRUCT_TMS 1 +#define HAVE_CLOCK_T 1 _ACEOF fi -# use gcc_cv_* here because this doesn't match the behavior of AC_CHECK_TYPE. -# revisit after autoconf 2.50. -echo "$as_me:$LINENO: checking for clock_t" >&5 -echo $ECHO_N "checking for clock_t... $ECHO_C" >&6 -if test "${gcc_cv_type_clock_t+set}" = set; then +echo "$as_me:$LINENO: checking for uchar" >&5 +echo $ECHO_N "checking for uchar... $ECHO_C" >&6 +if test "${gcc_cv_type_uchar+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - -cat >conftest.$ac_ext <<_ACEOF + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext @@ -11959,7 +8873,8 @@ cat >>conftest.$ac_ext <<_ACEOF int main () { -clock_t x; +if ((uchar *)0) return 0; + if (sizeof(uchar)) return 0; ; return 0; } @@ -11986,21 +8901,21 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - gcc_cv_type_clock_t=yes + ac_cv_type_uchar=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -gcc_cv_type_clock_t=no +ac_cv_type_uchar=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $gcc_cv_type_clock_t" >&5 -echo "${ECHO_T}$gcc_cv_type_clock_t" >&6 -if test $gcc_cv_type_clock_t = yes; then +echo "$as_me:$LINENO: result: $gcc_cv_type_uchar" >&5 +echo "${ECHO_T}$gcc_cv_type_uchar" >&6 +if test $ac_cv_type_uchar = yes; then cat >>confdefs.h <<\_ACEOF -#define HAVE_CLOCK_T 1 +#define HAVE_UCHAR 1 _ACEOF fi @@ -12170,15 +9085,6 @@ if test "${with_system_libunwind+set}" = set; then fi; -# config.gcc also contains tests of with_system_libunwind. -if test x$with_system_libunwind = xyes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_GETIPINFO 1 -_ACEOF - -fi - # -------------------------------------------------------- # Build, host, and target specific configuration fragments # -------------------------------------------------------- @@ -12276,14 +9182,6 @@ _ACEOF fi -if test x$use_long_long_for_widest_fast_int = xyes; then - -cat >>confdefs.h <<\_ACEOF -#define USE_LONG_LONG_FOR_WIDEST_FAST_INT 1 -_ACEOF - -fi - count=a for f in $host_xm_file; do count=${count}x @@ -12317,69 +9215,8 @@ if test "$host_xm_file" != "$build_xm_file"; then fi fi -case ${host} in - powerpc*-*-darwin*) - echo "$as_me:$LINENO: checking whether mcontext_t fields have underscores" >&5 -echo $ECHO_N "checking whether mcontext_t fields have underscores... $ECHO_C" >&6 -if test "${gcc_cv_mcontext_underscores+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF - -#include <sys/signal.h> -#include <ucontext.h> -int main() { mcontext_t m; if (m->ss.srr0) return 0; return 0; } - -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - gcc_cv_mcontext_underscores=no -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -gcc_cv_mcontext_underscores=yes -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $gcc_cv_mcontext_underscores" >&5 -echo "${ECHO_T}$gcc_cv_mcontext_underscores" >&6 - if test $gcc_cv_mcontext_underscores = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAS_MCONTEXT_T_UNDERSCORES -_ACEOF - - fi - ;; -esac - -# --------- -# Threading -# --------- - # Check if a valid thread package -case ${enable_threads} in +case ${enable_threads_flag} in "" | no) # No threads target_thread_file='single' @@ -12388,12 +9225,12 @@ case ${enable_threads} in # default target_thread_file='single' ;; - aix | dce | gnat | irix | posix | posix95 | rtems | \ + aix | dce | gnat | irix | posix | rtems | \ single | solaris | vxworks | win32 ) - target_thread_file=${enable_threads} + target_thread_file=${enable_threads_flag} ;; *) - echo "${enable_threads} is an unknown thread package" 1>&2 + echo "${enable_threads_flag} is an unknown thread package" 1>&2 exit 1 ;; esac @@ -12404,24 +9241,9 @@ if test x${thread_file} = x; then thread_file=${target_thread_file} fi -# Make gthr-default.h if we have a thread file. -gthread_flags= -if test $thread_file != single; then - rm -f gthr-default.h - echo "#include \"gthr-${thread_file}.h\"" > gthr-default.h - gthread_flags=-DHAVE_GTHR_DEFAULT -fi - - -# -------- -# UNSORTED -# -------- - -use_cxa_atexit=no if test x$enable___cxa_atexit = xyes || \ test x$enable___cxa_atexit = x -a x$default_use_cxa_atexit = xyes; then - if test x$host = x$target; then - echo "$as_me:$LINENO: checking for __cxa_atexit" >&5 + echo "$as_me:$LINENO: checking for __cxa_atexit" >&5 echo $ECHO_N "checking for __cxa_atexit... $ECHO_C" >&6 if test "${ac_cv_func___cxa_atexit+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -12512,167 +9334,15 @@ fi echo "$as_me:$LINENO: result: $ac_cv_func___cxa_atexit" >&5 echo "${ECHO_T}$ac_cv_func___cxa_atexit" >&6 if test $ac_cv_func___cxa_atexit = yes; then - use_cxa_atexit=yes -else - echo "__cxa_atexit can't be enabled on this target" -fi - - else - # We can't check for __cxa_atexit when building a cross, so assume - # it is available - use_cxa_atexit=yes - fi - if test x$use_cxa_atexit = xyes; then cat >>confdefs.h <<\_ACEOF -#define DEFAULT_USE_CXA_ATEXIT 2 -_ACEOF - - fi -fi - -use_getipinfo=yes -if test x$with_system_libunwind = xyes; then - if test x$host = x$target; then - echo "$as_me:$LINENO: checking for library containing _Unwind_GetIPInfo" >&5 -echo $ECHO_N "checking for library containing _Unwind_GetIPInfo... $ECHO_C" >&6 -if test "${ac_cv_search__Unwind_GetIPInfo+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_func_search_save_LIBS=$LIBS -ac_cv_search__Unwind_GetIPInfo=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any gcc2 internal prototype to avoid an error. */ -#ifdef __cplusplus -extern "C" -#endif -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char _Unwind_GetIPInfo (); -int -main () -{ -_Unwind_GetIPInfo (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_search__Unwind_GetIPInfo="none required" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -if test "$ac_cv_search__Unwind_GetIPInfo" = no; then - for ac_lib in unwind; do - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ +#define DEFAULT_USE_CXA_ATEXIT 1 _ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any gcc2 internal prototype to avoid an error. */ -#ifdef __cplusplus -extern "C" -#endif -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char _Unwind_GetIPInfo (); -int -main () -{ -_Unwind_GetIPInfo (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_search__Unwind_GetIPInfo="-l$ac_lib" -break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - done -fi -LIBS=$ac_func_search_save_LIBS -fi -echo "$as_me:$LINENO: result: $ac_cv_search__Unwind_GetIPInfo" >&5 -echo "${ECHO_T}$ac_cv_search__Unwind_GetIPInfo" >&6 -if test "$ac_cv_search__Unwind_GetIPInfo" != no; then - test "$ac_cv_search__Unwind_GetIPInfo" = "none required" || LIBS="$ac_cv_search__Unwind_GetIPInfo $LIBS" else - use_getipinfo=no -fi - - fi + echo "__cxa_atexit can't be enabled on this target" fi -if test x$use_getipinfo = xyes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_GETIPINFO 1 -_ACEOF - -else - echo "The system unwind library does not support _Unwind_GetIPInfo." fi # Look for a file containing extra machine modes. @@ -12686,13 +9356,6 @@ _ACEOF fi -# Convert extra_options into a form suitable for Makefile use. -extra_opt_files= -for f in $extra_options; do - extra_opt_files="$extra_opt_files \$(srcdir)/config/$f" -done - - # auto-host.h is the file containing items generated by autoconf and is # the first file included by config.h. # If host=build, it is correct to have bconfig include auto-host.h @@ -12701,6 +9364,7 @@ done if test x$host = x$build then build_auto=auto-host.h + FORBUILD=.. else # We create a subdir, then run autoconf in the subdir. # To prevent recursion we set host and build for the new @@ -12717,7 +9381,6 @@ else saved_CFLAGS="${CFLAGS}" CC="${CC_FOR_BUILD}" CFLAGS="${CFLAGS_FOR_BUILD}" \ ${realsrcdir}/configure \ - --enable-languages=${enable_languages-all} \ --target=$target_alias --host=$build_alias --build=$build_alias CFLAGS="${saved_CFLAGS}" @@ -12727,6 +9390,7 @@ else cd .. rm -rf $tempdir build_auto=auto-build.h + FORBUILD=../${build_subdir} fi @@ -12736,12 +9400,21 @@ host_xm_file="auto-host.h ansidecl.h ${host_xm_file}" build_xm_file="${build_auto} ansidecl.h ${build_xm_file}" # We don't want ansidecl.h in target files, write code there in ISO/GNU C. # put this back in temporarily. -xm_file="auto-host.h ansidecl.h ${xm_file}" +xm_file="ansidecl.h ${xm_file}" # -------- # UNSORTED # -------- +# Get the version trigger filename from the toplevel +if test "${with_gcc_version_trigger+set}" = set; then + gcc_version_trigger=$with_gcc_version_trigger +else + gcc_version_trigger=${srcdir}/version.c +fi +gcc_version_full=`grep version_string ${gcc_version_trigger} | sed -e 's/.*"\([^"]*\)".*/\1/'` +gcc_version=`echo ${gcc_version_full} | sed -e 's/\([^ ]*\) .*/\1/'` + # Compile in configure arguments. if test -f configargs.h ; then # Being re-configured. @@ -12770,6 +9443,11 @@ static const struct { EOF # Internationalization +PACKAGE=gcc +VERSION="$gcc_version" + + + # If we haven't got the data from the intl directory, # assume NLS is disabled. USE_NLS=no @@ -12779,9 +9457,8 @@ INCINTL= XGETTEXT= GMSGFMT= POSUB= - -if test -f ../intl/config.intl; then - . ../intl/config.intl +if test -f ../intl/config.intl; then + . ../intl/config.intl fi echo "$as_me:$LINENO: checking whether NLS is requested" >&5 echo $ECHO_N "checking whether NLS is requested... $ECHO_C" >&6 @@ -12813,8 +9490,8 @@ echo $ECHO_N "checking for catalogs to be installed... $ECHO_C" >&6 # by the backticks, then collapsed again by the double quotes, # leaving us with one backslash in the sed expression (right # before the dot that mustn't act as a wildcard). - cat=`echo $cat | sed -e "s!$srcdir/po/!!" -e "s!\\\\.po!.gmo!"` - lang=`echo $cat | sed -e "s!\\\\.gmo!!"` + cat=`echo $cat | sed -e "s!$srcdir/!!" -e "s!\\\\.po!.gmo!"` + lang=`echo $cat | sed -e 's!po/!!' -e "s!\\\\.gmo!!"` # The user is allowed to set LINGUAS to a list of languages to # install catalogs for. If it's empty that means "all of them." if test "x$LINGUAS" = x; then @@ -12831,16 +9508,6 @@ echo $ECHO_N "checking for catalogs to be installed... $ECHO_C" >&6 LINGUAS="$XLINGUAS" echo "$as_me:$LINENO: result: $LINGUAS" >&5 echo "${ECHO_T}$LINGUAS" >&6 - - - DATADIRNAME=share - - INSTOBJEXT=.mo - - GENCAT=gencat - - CATOBJEXT=.gmo - fi # If LIBINTL contains LIBICONV, then clear LIBICONV so we don't get @@ -12849,23 +9516,25 @@ case "$LIBINTL" in *$LIBICONV*) LIBICONV= ;; esac -# Check whether --enable-secureplt or --disable-secureplt was given. -if test "${enable_secureplt+set}" = set; then - enableval="$enable_secureplt" - -fi; - # Windows32 Registry support for specifying GCC installation paths. # Check whether --enable-win32-registry or --disable-win32-registry was given. if test "${enable_win32_registry+set}" = set; then enableval="$enable_win32_registry" fi; - case $host_os in - win32 | pe | cygwin* | mingw32* | uwin*) - if test "x$enable_win32_registry" != xno; then - echo "$as_me:$LINENO: checking for library containing RegOpenKeyExA" >&5 + win32 | pe | cygwin* | mingw32* | uwin*) +echo "$as_me:$LINENO: checking whether windows registry support is requested" >&5 +echo $ECHO_N "checking whether windows registry support is requested... $ECHO_C" >&6 +if test "x$enable_win32_registry" != xno; then + +cat >>confdefs.h <<\_ACEOF +#define ENABLE_WIN32_REGISTRY 1 +_ACEOF + + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + echo "$as_me:$LINENO: checking for library containing RegOpenKeyExA" >&5 echo $ECHO_N "checking for library containing RegOpenKeyExA... $ECHO_C" >&6 if test "${ac_cv_search_RegOpenKeyExA+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -12989,29 +9658,41 @@ echo "${ECHO_T}$ac_cv_search_RegOpenKeyExA" >&6 if test "$ac_cv_search_RegOpenKeyExA" != no; then test "$ac_cv_search_RegOpenKeyExA" = "none required" || LIBS="$ac_cv_search_RegOpenKeyExA $LIBS" -else - enable_win32_registry=no fi - fi - - if test "x$enable_win32_registry" != xno; then - -cat >>confdefs.h <<\_ACEOF -#define ENABLE_WIN32_REGISTRY 1 -_ACEOF +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +# Check if user specified a different registry key. +case "x${enable_win32_registry}" in +x | xyes) + # default. + gcc_cv_win32_registry_key="$VERSION" + ;; +xno) + # no registry lookup. + gcc_cv_win32_registry_key='' + ;; +*) + # user-specified key. + gcc_cv_win32_registry_key="$enable_win32_registry" + ;; +esac - if test "x$enable_win32_registry" != xyes \ - && test "x$enable_win32_registry" != x; then +if test "x$enable_win32_registry" != xno; then + echo "$as_me:$LINENO: checking registry key on windows hosts" >&5 +echo $ECHO_N "checking registry key on windows hosts... $ECHO_C" >&6 cat >>confdefs.h <<_ACEOF -#define WIN32_REGISTRY_KEY "$enable_win32_registry" +#define WIN32_REGISTRY_KEY "$gcc_cv_win32_registry_key" _ACEOF - fi - fi - ;; + echo "$as_me:$LINENO: result: $gcc_cv_win32_registry_key" >&5 +echo "${ECHO_T}$gcc_cv_win32_registry_key" >&6 +fi +;; esac # Get an absolute path to the GCC top-level source directory @@ -13041,33 +9722,37 @@ do done tmake_file="${tmake_file_}" +symbolic_link='ln -s' + # If the host doesn't support symlinks, modify CC in # FLAGS_TO_PASS so CC="stage1/xgcc -Bstage1/" works. # Otherwise, we can use "CC=$(CC)". rm -f symtest.tem -case "$LN_S" in - *-s*) - cc_set_by_configure="\$(CC)" - quoted_cc_set_by_configure="\$(CC)" - stage_prefix_set_by_configure="\$(STAGE_PREFIX)" - quoted_stage_prefix_set_by_configure="\$(STAGE_PREFIX)" - ;; - *) - cc_set_by_configure="\`case '\$(CC)' in stage*) echo '\$(CC)' | sed -e 's|stage|../stage|g';; *) echo '\$(CC)';; esac\`" - quoted_cc_set_by_configure="\\\`case '\\\$(CC)' in stage*) echo '\\\$(CC)' | sed -e 's|stage|../stage|g';; *) echo '\\\$(CC)';; esac\\\`" - stage_prefix_set_by_configure="\`case '\$(STAGE_PREFIX)' in stage*) echo '\$(STAGE_PREFIX)' | sed -e 's|stage|../stage|g';; *) echo '\$(STAGE_PREFIX)';; esac\`" - quoted_stage_prefix_set_by_configure="\\\`case '\\\$(STAGE_PREFIX)' in stage*) echo '\\\$(STAGE_PREFIX)' | sed -e 's|stage|../stage|g';; *) echo '\\\$(STAGE_PREFIX)';; esac\\\`" - ;; -esac - -# This is a terrible hack which will go away some day. -host_cc_for_libada=${CC} - +if $symbolic_link $srcdir/gcc.c symtest.tem 2>/dev/null +then + cc_set_by_configure="\$(CC)" + quoted_cc_set_by_configure="\$(CC)" + stage_prefix_set_by_configure="\$(STAGE_PREFIX)" + quoted_stage_prefix_set_by_configure="\$(STAGE_PREFIX)" +else + rm -f symtest.tem + if cp -p $srcdir/gcc.c symtest.tem 2>/dev/null + then + symbolic_link="cp -p" + else + symbolic_link="cp" + fi + cc_set_by_configure="\`case '\$(CC)' in stage*) echo '\$(CC)' | sed -e 's|stage|../stage|g';; *) echo '\$(CC)';; esac\`" + quoted_cc_set_by_configure="\\\`case '\\\$(CC)' in stage*) echo '\\\$(CC)' | sed -e 's|stage|../stage|g';; *) echo '\\\$(CC)';; esac\\\`" + stage_prefix_set_by_configure="\`case '\$(STAGE_PREFIX)' in stage*) echo '\$(STAGE_PREFIX)' | sed -e 's|stage|../stage|g';; *) echo '\$(STAGE_PREFIX)';; esac\`" + quoted_stage_prefix_set_by_configure="\\\`case '\\\$(STAGE_PREFIX)' in stage*) echo '\\\$(STAGE_PREFIX)' | sed -e 's|stage|../stage|g';; *) echo '\\\$(STAGE_PREFIX)';; esac\\\`" +fi +rm -f symtest.tem out_object_file=`basename $out_file .c`.o -tm_file_list="options.h" -tm_include_list="options.h" +tm_file_list= +tm_include_list= for f in $tm_file; do case $f in defaults.h ) @@ -13156,21 +9841,11 @@ done CROSS= ALL=all.internal SYSTEM_HEADER_DIR='$(NATIVE_SYSTEM_HEADER_DIR)' - -if test "x$with_build_sysroot" != x; then - build_system_header_dir=$with_build_sysroot'$(NATIVE_SYSTEM_HEADER_DIR)' -else - # This value is used, even on a native system, because - # CROSS_SYSTEM_HEADER_DIR is just - # $(TARGET_SYSTEM_ROOT)$(NATIVE_SYSTEM_HEADER_DIR). - build_system_header_dir='$(CROSS_SYSTEM_HEADER_DIR)' -fi - if test x$host != x$target then CROSS="-DCROSS_COMPILE" ALL=all.cross - SYSTEM_HEADER_DIR=$build_system_header_dir + SYSTEM_HEADER_DIR='$(CROSS_SYSTEM_HEADER_DIR)' case "$host","$target" in # Darwin crosses can use the host system's libraries and headers, # because of the fat library support. Of course, it must be the @@ -13192,7 +9867,8 @@ then CROSS="$CROSS -DNATIVE_CROSS" ;; esac elif test "x$TARGET_SYSTEM_ROOT" != x; then - SYSTEM_HEADER_DIR=$build_system_header_dir + # This is just $(TARGET_SYSTEM_ROOT)$(NATIVE_SYSTEM_HEADER_DIR) + SYSTEM_HEADER_DIR='$(CROSS_SYSTEM_HEADER_DIR)' fi # If this is a cross-compiler that does not @@ -13203,11 +9879,11 @@ fi # then define inhibit_libc in LIBGCC2_CFLAGS. # This prevents libgcc2 from containing any code which requires libc # support. -inhibit_libc=false +inhibit_libc= if { { test x$host != x$target && test "x$with_sysroot" = x ; } || test x$with_newlib = xyes ; } && { test "x$with_headers" = x || test "x$with_headers" = xno ; } ; then - inhibit_libc=true + inhibit_libc=-Dinhibit_libc fi @@ -13216,8 +9892,11 @@ fi # Also, we cannot run fixincludes or fix-header. # These are the normal (build=host) settings: +BUILD_PREFIX= +BUILD_PREFIX_1=ignore- CC_FOR_BUILD='$(CC)' BUILD_CFLAGS='$(ALL_CFLAGS)' + STMP_FIXINC=stmp-fixinc # Possibly disable fixproto, on a per-target basis. @@ -13234,12 +9913,13 @@ esac # And these apply if build != host, or we are generating coverage data if test x$build != x$host || test "x$coverage_flags" != x then + BUILD_PREFIX=build- + BUILD_PREFIX_1=build- BUILD_CFLAGS='$(INTERNAL_CFLAGS) $(T_CFLAGS) $(CFLAGS_FOR_BUILD)' if test "x$TARGET_SYSTEM_ROOT" = x; then - if test "x$STMP_FIXPROTO" != x; then - STMP_FIXPROTO=stmp-install-fixproto - fi + STMP_FIXINC= + STMP_FIXPROTO= fi fi @@ -13251,13 +9931,6 @@ for file in ${extra_headers} ; do extra_headers_list="${extra_headers_list} \$(srcdir)/config/${cpu_type}/${file}" done -# Define collect2 in Makefile. -case $host_can_use_collect2 in - no) collect2= ;; - *) collect2='collect2$(exeext)' ;; -esac - - # Add a definition of USE_COLLECT2 if system wants one. case $use_collect2 in no) use_collect2= ;; @@ -13265,20 +9938,9 @@ case $use_collect2 in *) host_xm_defines="${host_xm_defines} USE_COLLECT2" xm_defines="${xm_defines} USE_COLLECT2" - case $host_can_use_collect2 in - no) - { { echo "$as_me:$LINENO: error: collect2 is required but cannot be built on this system" >&5 -echo "$as_me: error: collect2 is required but cannot be built on this system" >&2;} - { (exit 1); exit 1; }; } - ;; - esac ;; esac -# --------------------------- -# Assembler & linker features -# --------------------------- - # Identify the assembler which will work hand-in-glove with the newly # built GCC, so that we can examine its features. This is the assembler # which will be driven by the driver program. @@ -13286,87 +9948,30 @@ esac # If build != host, and we aren't building gas in-tree, we identify a # build->target assembler and hope that it will have the same features # as the host->target assembler we'll be using. +echo "$as_me:$LINENO: checking what assembler to use" >&5 +echo $ECHO_N "checking what assembler to use... $ECHO_C" >&6 +in_tree_gas=no +gcc_cv_as= gcc_cv_gas_major_version= gcc_cv_gas_minor_version= gcc_cv_as_gas_srcdir=`echo $srcdir | sed -e 's,/gcc$,,'`/gas - -if test "${gcc_cv_as+set}" = set; then - : -else - if test -x "$DEFAULT_ASSEMBLER"; then gcc_cv_as="$DEFAULT_ASSEMBLER" -elif test -f $gcc_cv_as_gas_srcdir/configure.in \ - && test -f ../gas/Makefile \ - && test x$build = x$host; then - gcc_cv_as=../gas/as-new$build_exeext -elif test -x as$build_exeext; then +elif test -x "$AS"; then + gcc_cv_as="$AS" +elif test -x as$host_exeext; then # Build using assembler in the current directory. - gcc_cv_as=./as$build_exeext -elif test -x $AS_FOR_TARGET; then - gcc_cv_as="$AS_FOR_TARGET" -else - # Extract the first word of "$AS_FOR_TARGET", so it can be a program name with args. -set dummy $AS_FOR_TARGET; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_path_gcc_cv_as+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - case $gcc_cv_as in - [\\/]* | ?:[\\/]*) - ac_cv_path_gcc_cv_as="$gcc_cv_as" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_gcc_cv_as="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - - ;; -esac -fi -gcc_cv_as=$ac_cv_path_gcc_cv_as - -if test -n "$gcc_cv_as"; then - echo "$as_me:$LINENO: result: $gcc_cv_as" >&5 -echo "${ECHO_T}$gcc_cv_as" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - -fi -fi - - -ORIGINAL_AS_FOR_TARGET=$gcc_cv_as - - -echo "$as_me:$LINENO: checking what assembler to use" >&5 -echo $ECHO_N "checking what assembler to use... $ECHO_C" >&6 -if test "$gcc_cv_as" = ../gas/as-new$build_exeext; then - # Single tree build which includes gas. We want to prefer it - # over whatever linker top-level may have detected, since - # we'll use what we're building after installation anyway. - echo "$as_me:$LINENO: result: newly built gas" >&5 -echo "${ECHO_T}newly built gas" >&6 + gcc_cv_as=./as$host_exeext +elif test -f $gcc_cv_as_gas_srcdir/configure.in \ + && test -f ../gas/Makefile; then + # Single tree build which includes gas. in_tree_gas=yes gcc_cv_as_bfd_srcdir=`echo $srcdir | sed -e 's,/gcc$,,'`/bfd for f in $gcc_cv_as_bfd_srcdir/configure \ $gcc_cv_as_gas_srcdir/configure \ $gcc_cv_as_gas_srcdir/configure.in \ $gcc_cv_as_gas_srcdir/Makefile.in ; do - gcc_cv_gas_version=`sed -n -e 's/^[ ]*\(VERSION=[0-9]*\.[0-9]*.*\)/\1/p' < $f` + gcc_cv_gas_version=`grep '^VERSION=[0-9]*\.[0-9]*' $f` if test x$gcc_cv_gas_version != x; then break fi @@ -13381,6 +9986,8 @@ gcc_cv_gas_vers=`expr \( \( $gcc_cv_gas_major_version \* 1000 \) \ + $gcc_cv_gas_minor_version \) \* 1000 \ + $gcc_cv_gas_patch_version` + rm -f as$host_exeext + $symbolic_link ../gas/as-new$host_exeext as$host_exeext 2>/dev/null in_tree_gas_is_elf=no if grep 'obj_format = elf' ../gas/Makefile > /dev/null \ || (grep 'obj_format = multi' ../gas/Makefile \ @@ -13388,12 +9995,78 @@ gcc_cv_gas_vers=`expr \( \( $gcc_cv_gas_major_version \* 1000 \) \ then in_tree_gas_is_elf=yes fi -else - echo "$as_me:$LINENO: result: $gcc_cv_as" >&5 -echo "${ECHO_T}$gcc_cv_as" >&6 - in_tree_gas=no fi +if test "x$gcc_cv_as" = x; then + # Search the same directories that the installed compiler will + # search. Else we may find the wrong assembler and lose. If we + # do not find a suitable assembler binary, then try the user's + # path. + # + # Also note we have to check MD_EXEC_PREFIX before checking the + # user's path. Unfortunately, there is no good way to get at the + # value of MD_EXEC_PREFIX here. So we do a brute force search + # through all the known MD_EXEC_PREFIX values. Ugh. This needs + # to be fixed as part of the make/configure rewrite too. + + if test "x$exec_prefix" = xNONE; then + if test "x$prefix" = xNONE; then + test_prefix=/usr/local + else + test_prefix=$prefix + fi + else + test_prefix=$exec_prefix + fi + + # If the loop below does not find an assembler, then use whatever + # one we can find in the users's path. + # user's path. + if test "x$program_prefix" != xNONE; then + gcc_cv_as=${program_prefix}as$host_exeext + else + gcc_cv_as=`echo as | sed ${program_transform_name}`$host_exeext + fi + + test_dirs="$test_prefix/libexec/gcc/$target_noncanonical/$gcc_version \ + $test_prefix/libexec/gcc/$target_noncanonical \ + /usr/lib/gcc/$target_noncanonical/$gcc_version \ + /usr/lib/gcc/$target_noncanonical \ + $test_prefix/$target_noncanonical/bin/$target_noncanonical/$gcc_version \ + $test_prefix/$target_noncanonical/bin" + + if test x$host = x$target; then + test_dirs="$test_dirs \ + /usr/libexec \ + /usr/ccs/gcc \ + /usr/ccs/bin \ + /udk/usr/ccs/bin \ + /bsd43/usr/lib/cmplrs/cc \ + /usr/cross64/usr/bin \ + /usr/lib/cmplrs/cc \ + /sysv/usr/lib/cmplrs/cc \ + /svr4/usr/lib/cmplrs/cc \ + /usr/bin" + fi + + for dir in $test_dirs; do + if test -x $dir/as$host_exeext; then + gcc_cv_as=$dir/as$host_exeext + break; + fi + done +fi +case $in_tree_gas in + yes) + echo "$as_me:$LINENO: result: \"newly built gas\"" >&5 +echo "${ECHO_T}\"newly built gas\"" >&6 + ;; + no) + echo "$as_me:$LINENO: result: $gcc_cv_as" >&5 +echo "${ECHO_T}$gcc_cv_as" >&6 + ;; +esac + # Identify the linker which will work hand-in-glove with the newly # built GCC, so that we can examine its features. This is the linker # which will be driven by the driver program. @@ -13401,248 +10074,166 @@ fi # If build != host, and we aren't building gas in-tree, we identify a # build->target linker and hope that it will have the same features # as the host->target linker we'll be using. +echo "$as_me:$LINENO: checking what linker to use" >&5 +echo $ECHO_N "checking what linker to use... $ECHO_C" >&6 +in_tree_ld=no +gcc_cv_ld= gcc_cv_gld_major_version= gcc_cv_gld_minor_version= gcc_cv_ld_gld_srcdir=`echo $srcdir | sed -e 's,/gcc$,,'`/ld gcc_cv_ld_bfd_srcdir=`echo $srcdir | sed -e 's,/gcc$,,'`/bfd - -if test "${gcc_cv_ld+set}" = set; then - : -else - if test -x "$DEFAULT_LINKER"; then gcc_cv_ld="$DEFAULT_LINKER" -elif test -f $gcc_cv_ld_gld_srcdir/configure.in \ - && test -f ../ld/Makefile \ - && test x$build = x$host; then - gcc_cv_ld=../ld/ld-new$build_exeext -elif test -x collect-ld$build_exeext; then +elif test -x "$LD"; then + gcc_cv_ld="$LD" +elif test -x collect-ld$host_exeext; then # Build using linker in the current directory. - gcc_cv_ld=./collect-ld$build_exeext -elif test -x $LD_FOR_TARGET; then - gcc_cv_ld="$LD_FOR_TARGET" -else - # Extract the first word of "$LD_FOR_TARGET", so it can be a program name with args. -set dummy $LD_FOR_TARGET; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_path_gcc_cv_ld+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - case $gcc_cv_ld in - [\\/]* | ?:[\\/]*) - ac_cv_path_gcc_cv_ld="$gcc_cv_ld" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_gcc_cv_ld="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - - ;; -esac -fi -gcc_cv_ld=$ac_cv_path_gcc_cv_ld - -if test -n "$gcc_cv_ld"; then - echo "$as_me:$LINENO: result: $gcc_cv_ld" >&5 -echo "${ECHO_T}$gcc_cv_ld" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - -fi -fi - - -ORIGINAL_LD_FOR_TARGET=$gcc_cv_ld - - -echo "$as_me:$LINENO: checking what linker to use" >&5 -echo $ECHO_N "checking what linker to use... $ECHO_C" >&6 -if test "$gcc_cv_ld" = ../ld/ld-new$build_exeext; then - # Single tree build which includes ld. We want to prefer it - # over whatever linker top-level may have detected, since - # we'll use what we're building after installation anyway. - echo "$as_me:$LINENO: result: newly built ld" >&5 -echo "${ECHO_T}newly built ld" >&6 + gcc_cv_ld=./collect-ld$host_exeext +elif test -f $gcc_cv_ld_gld_srcdir/configure.in \ + && test -f ../ld/Makefile; then + # Single tree build which includes ld. in_tree_ld=yes in_tree_ld_is_elf=no if (grep 'EMUL = .*elf' ../ld/Makefile \ - || grep 'EMUL = .*linux' ../ld/Makefile \ - || grep 'EMUL = .*lynx' ../ld/Makefile) > /dev/null; then + || grep 'EMUL = .*linux' ../ld/Makefile) > /dev/null; then in_tree_ld_is_elf=yes fi for f in $gcc_cv_ld_bfd_srcdir/configure $gcc_cv_ld_gld_srcdir/configure $gcc_cv_ld_gld_srcdir/configure.in $gcc_cv_ld_gld_srcdir/Makefile.in do - gcc_cv_gld_version=`sed -n -e 's/^[ ]*\(VERSION=[0-9]*\.[0-9]*.*\)/\1/p' < $f` + gcc_cv_gld_version=`grep '^VERSION=[0-9]*\.[0-9]*' $f` if test x$gcc_cv_gld_version != x; then break fi done gcc_cv_gld_major_version=`expr "$gcc_cv_gld_version" : "VERSION=\([0-9]*\)"` gcc_cv_gld_minor_version=`expr "$gcc_cv_gld_version" : "VERSION=[0-9]*\.\([0-9]*\)"` -else - echo "$as_me:$LINENO: result: $gcc_cv_ld" >&5 -echo "${ECHO_T}$gcc_cv_ld" >&6 - in_tree_ld=no -fi - -# Figure out what nm we will be using. -gcc_cv_binutils_srcdir=`echo $srcdir | sed -e 's,/gcc$,,'`/binutils -if test "${gcc_cv_nm+set}" = set; then - : -else - -if test -f $gcc_cv_binutils_srcdir/configure.in \ - && test -f ../binutils/Makefile \ - && test x$build = x$host; then - gcc_cv_nm=../binutils/nm-new$build_exeext -elif test -x nm$build_exeext; then - gcc_cv_nm=./nm$build_exeext -elif test -x $NM_FOR_TARGET; then - gcc_cv_nm="$NM_FOR_TARGET" -else - # Extract the first word of "$NM_FOR_TARGET", so it can be a program name with args. -set dummy $NM_FOR_TARGET; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_path_gcc_cv_nm+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - case $gcc_cv_nm in - [\\/]* | ?:[\\/]*) - ac_cv_path_gcc_cv_nm="$gcc_cv_nm" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_gcc_cv_nm="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done + rm -f collect-ld$host_exeext + $symbolic_link ../ld/ld-new$host_exeext collect-ld$host_exeext \ + 2>/dev/null +fi + +if test "x$gcc_cv_ld" = x; then + # Search the same directories that the installed compiler will + # search. Else we may find the wrong linker and lose. If we + # do not find a suitable linker binary, then try the user's + # path. + # + # Also note we have to check MD_EXEC_PREFIX before checking the + # user's path. Unfortunately, there is no good way to get at the + # value of MD_EXEC_PREFIX here. So we do a brute force search + # through all the known MD_EXEC_PREFIX values. Ugh. This needs + # to be fixed as part of the make/configure rewrite too. + + if test "x$exec_prefix" = xNONE; then + if test "x$prefix" = xNONE; then + test_prefix=/usr/local + else + test_prefix=$prefix + fi + else + test_prefix=$exec_prefix + fi - ;; -esac -fi -gcc_cv_nm=$ac_cv_path_gcc_cv_nm + # If the loop below does not find an linker, then use whatever + # one we can find in the users's path. + # user's path. + if test "x$program_prefix" != xNONE; then + gcc_cv_ld=${program_prefix}ld$host_exeext + else + gcc_cv_ld=`echo ld | sed ${program_transform_name}`$host_exeext + fi -if test -n "$gcc_cv_nm"; then - echo "$as_me:$LINENO: result: $gcc_cv_nm" >&5 -echo "${ECHO_T}$gcc_cv_nm" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi + test_dirs="$test_prefix/libexec/gcc/$target_noncanonical/$gcc_version \ + $test_prefix/libexec/gcc/$target_noncanonical \ + /usr/lib/gcc/$target_noncanonical/$gcc_version \ + /usr/lib/gcc/$target_noncanonical \ + $test_prefix/$target_noncanonical/bin/$target_noncanonical/$gcc_version \ + $test_prefix/$target_noncanonical/bin" + + if test x$host = x$target; then + test_dirs="$test_dirs \ + /usr/libexec \ + /usr/ccs/gcc \ + /usr/ccs/bin \ + /udk/usr/ccs/bin \ + /bsd43/usr/lib/cmplrs/cc \ + /usr/cross64/usr/bin \ + /usr/lib/cmplrs/cc \ + /sysv/usr/lib/cmplrs/cc \ + /svr4/usr/lib/cmplrs/cc \ + /usr/bin" + fi + for dir in $test_dirs; do + if test -x $dir/ld$host_exeext; then + gcc_cv_ld=$dir/ld$host_exeext + break; + fi + done fi -fi - +case $in_tree_ld in + yes) + echo "$as_me:$LINENO: result: \"newly built ld\"" >&5 +echo "${ECHO_T}\"newly built ld\"" >&6 + ;; + no) + echo "$as_me:$LINENO: result: $gcc_cv_ld" >&5 +echo "${ECHO_T}$gcc_cv_ld" >&6 + ;; +esac +# Figure out what nm we will be using. +gcc_cv_binutils_srcdir=`echo $srcdir | sed -e 's,/gcc$,,'`/binutils echo "$as_me:$LINENO: checking what nm to use" >&5 echo $ECHO_N "checking what nm to use... $ECHO_C" >&6 -if test "$gcc_cv_nm" = ../binutils/nm-new$build_exeext; then +in_tree_nm=no +if test -x nm$host_exeext; then + gcc_cv_nm=./nm$host_exeext +elif test -f $gcc_cv_binutils_srcdir/configure.in \ + && test -f ../binutils/Makefile; then # Single tree build which includes binutils. - echo "$as_me:$LINENO: result: newly built nm" >&5 -echo "${ECHO_T}newly built nm" >&6 in_tree_nm=yes -else - echo "$as_me:$LINENO: result: $gcc_cv_nm" >&5 -echo "${ECHO_T}$gcc_cv_nm" >&6 - in_tree_nm=no -fi - -ORIGINAL_NM_FOR_TARGET=$gcc_cv_nm - - -# Figure out what objdump we will be using. -if test "${gcc_cv_objdump+set}" = set; then - : -else - -if test -f $gcc_cv_binutils_srcdir/configure.in \ - && test -f ../binutils/Makefile \ - && test x$build = x$host; then - # Single tree build which includes binutils. - gcc_cv_objdump=../binutils/objdump$build_exeext -elif test -x objdump$build_exeext; then - gcc_cv_objdump=./objdump$build_exeext -elif test -x $OBJDUMP_FOR_TARGET; then - gcc_cv_objdump="$OBJDUMP_FOR_TARGET" -else - # Extract the first word of "$OBJDUMP_FOR_TARGET", so it can be a program name with args. -set dummy $OBJDUMP_FOR_TARGET; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_path_gcc_cv_objdump+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - case $gcc_cv_objdump in - [\\/]* | ?:[\\/]*) - ac_cv_path_gcc_cv_objdump="$gcc_cv_objdump" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_gcc_cv_objdump="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - - ;; + gcc_cv_nm=./nm$host_exeext + rm -f nm$host_exeext + $symbolic_link ../binutils/nm-new$host_exeext nm$host_exeext 2>/dev/null +elif test "x$program_prefix" != xNONE; then + gcc_cv_nm=${program_prefix}nm$host_exeext +else + gcc_cv_nm=`echo nm | sed ${program_transform_name}`$host_exeext +fi +case $in_tree_nm in + yes) echo "$as_me:$LINENO: result: \"newly built nm\"" >&5 +echo "${ECHO_T}\"newly built nm\"" >&6 ;; + no) echo "$as_me:$LINENO: result: $gcc_cv_nm" >&5 +echo "${ECHO_T}$gcc_cv_nm" >&6 ;; esac -fi -gcc_cv_objdump=$ac_cv_path_gcc_cv_objdump - -if test -n "$gcc_cv_objdump"; then - echo "$as_me:$LINENO: result: $gcc_cv_objdump" >&5 -echo "${ECHO_T}$gcc_cv_objdump" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - -fi -fi - +# Figure out what objdump we will be using. echo "$as_me:$LINENO: checking what objdump to use" >&5 echo $ECHO_N "checking what objdump to use... $ECHO_C" >&6 -if test "$gcc_cv_objdump" = ../binutils/objdump$build_exeext; then +in_tree_objdump=no +if test -x objdump$host_exeext; then + gcc_cv_objdump=./objdump$host_exeext +elif test -f $gcc_cv_binutils_srcdir/configure.in \ + && test -f ../binutils/Makefile; then # Single tree build which includes binutils. - echo "$as_me:$LINENO: result: newly built objdump" >&5 -echo "${ECHO_T}newly built objdump" >&6 -elif test x$gcc_cv_objdump = x; then - echo "$as_me:$LINENO: result: not found" >&5 -echo "${ECHO_T}not found" >&6 -else - echo "$as_me:$LINENO: result: $gcc_cv_objdump" >&5 -echo "${ECHO_T}$gcc_cv_objdump" >&6 -fi + in_tree_objdump=yes + gcc_cv_objdump=./objdump$host_exeext + rm -f objdump$host_exeext + $symbolic_link ../binutils/objdump$host_exeext \ + objdump$host_exeext 2>/dev/null +elif test "x$program_prefix" != xNONE; then + gcc_cv_objdump=${program_prefix}objdump$host_exeext +else + gcc_cv_objdump=`echo objdump | \ + sed ${program_transform_name}`$host_exeext +fi +case $in_tree_objdump in + yes) echo "$as_me:$LINENO: result: \"newly built objdump\"" >&5 +echo "${ECHO_T}\"newly built objdump\"" >&6 ;; + no) echo "$as_me:$LINENO: result: $gcc_cv_objdump" >&5 +echo "${ECHO_T}$gcc_cv_objdump" >&6 ;; +esac # Figure out what assembler alignment features are present. echo "$as_me:$LINENO: checking assembler for .balign and .p2align" >&5 @@ -13806,43 +10397,6 @@ _ACEOF fi -echo "$as_me:$LINENO: checking assembler for .weakref" >&5 -echo $ECHO_N "checking assembler for .weakref... $ECHO_C" >&6 -if test "${gcc_cv_as_weakref+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_as_weakref=no - if test $in_tree_gas = yes; then - if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 17 \) \* 1000 + 0` - then gcc_cv_as_weakref=yes -fi - elif test x$gcc_cv_as != x; then - echo ' .weakref foobar, barfnot' > conftest.s - if { ac_try='$gcc_cv_as -o conftest.o conftest.s >&5' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } - then - gcc_cv_as_weakref=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_as_weakref" >&5 -echo "${ECHO_T}$gcc_cv_as_weakref" >&6 -if test $gcc_cv_as_weakref = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_GAS_WEAKREF 1 -_ACEOF - -fi - echo "$as_me:$LINENO: checking assembler for .nsubspa comdat" >&5 echo $ECHO_N "checking assembler for .nsubspa comdat... $ECHO_C" >&6 if test "${gcc_cv_as_nsubspa_comdat+set}" = set; then @@ -13942,12 +10496,8 @@ else -e 's,^.*[ ]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)$,\1,p' \ -e 's,^.*[ ]\([0-9][0-9]*\.[0-9][0-9]*\)[ ].*$,\1,p' \ -e 's,^.*[ ]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)[ ].*$,\1,p' \ - -e 's,^.*[ ]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)[ ].*$,\1,p' \ - -e 's,^.*[ ]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)[ -].*$,\1,p'` + -e 's,^.*[ ]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)[ ].*$,\1,p'` ld_date=`echo $ld_ver | sed -n 's,^.*\([2-9][0-9][0-9][0-9]\)[-]*\([01][0-9]\)[-]*\([0-3][0-9]\).*$,\1\2\3,p'` - ld_vers_major=`expr "$ld_vers" : '\([0-9]*\)'` - ld_vers_minor=`expr "$ld_vers" : '[0-9]*\.\([0-9]*\)'` - ld_vers_patch=`expr "$ld_vers" : '[0-9]*\.[0-9]*\.\([0-9]*\)'` if test 0"$ld_date" -lt 20020404; then if test -n "$ld_date"; then # If there was date string, but was earlier than 2002-04-04, fail @@ -13956,6 +10506,9 @@ else # If there was no date string nor ld version number, something is wrong gcc_cv_ld_hidden=no else + ld_vers_major=`expr "$ld_vers" : '\([0-9]*\)'` + ld_vers_minor=`expr "$ld_vers" : '[0-9]*\.\([0-9]*\)'` + ld_vers_patch=`expr "$ld_vers" : '[0-9]*\.[0-9]*\.\([0-9]*\)'` test -z "$ld_vers_patch" && ld_vers_patch=0 if test "$ld_vers_major" -lt 2; then gcc_cv_ld_hidden=no @@ -13982,7 +10535,6 @@ echo "$as_me:$LINENO: result: $gcc_cv_ld_hidden" >&5 echo "${ECHO_T}$gcc_cv_ld_hidden" >&6 libgcc_visibility=no - if test $gcc_cv_as_hidden = yes && test $gcc_cv_ld_hidden = yes; then libgcc_visibility=yes @@ -14115,14 +10667,11 @@ cat > conftest.big <<EOF EOF # If the assembler didn't choke, and we can objdump, # and we got the correct data, then succeed. - # The text in the here-document typically retains its unix-style line - # endings, while the output of objdump will use host line endings. - # Therefore, use diff -b for the comparisons. if test x$gcc_cv_objdump != x \ && $gcc_cv_objdump -s -j .eh_frame conftest.o 2>/dev/null \ | tail -3 > conftest.got \ - && { diff -b conftest.lit conftest.got > /dev/null 2>&1 \ - || diff -b conftest.big conftest.got > /dev/null 2>&1; } + && { cmp conftest.lit conftest.got > /dev/null 2>&1 \ + || cmp conftest.big conftest.got > /dev/null 2>&1; } then gcc_cv_as_eh_frame=yes elif { ac_try='$gcc_cv_as -o conftest.o --traditional-format /dev/null' @@ -14186,137 +10735,12 @@ fi echo "$as_me:$LINENO: result: $gcc_cv_as_shf_merge" >&5 echo "${ECHO_T}$gcc_cv_as_shf_merge" >&6 -if test $gcc_cv_as_shf_merge = no; then - echo "$as_me:$LINENO: checking assembler for section merging support" >&5 -echo $ECHO_N "checking assembler for section merging support... $ECHO_C" >&6 -if test "${gcc_cv_as_shf_merge+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_as_shf_merge=no - if test $in_tree_gas = yes; then - if test $in_tree_gas_is_elf = yes \ - && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 12 \) \* 1000 + 0` - then gcc_cv_as_shf_merge=yes -fi - elif test x$gcc_cv_as != x; then - echo '.section .rodata.str, "aMS", %progbits, 1' > conftest.s - if { ac_try='$gcc_cv_as --fatal-warnings -o conftest.o conftest.s >&5' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } - then - gcc_cv_as_shf_merge=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_as_shf_merge" >&5 -echo "${ECHO_T}$gcc_cv_as_shf_merge" >&6 - -fi cat >>confdefs.h <<_ACEOF #define HAVE_GAS_SHF_MERGE `if test $gcc_cv_as_shf_merge = yes; then echo 1; else echo 0; fi` _ACEOF -echo "$as_me:$LINENO: checking assembler for COMDAT group support" >&5 -echo $ECHO_N "checking assembler for COMDAT group support... $ECHO_C" >&6 -if test "${gcc_cv_as_comdat_group+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_as_comdat_group=no - if test $in_tree_gas = yes; then - if test $in_tree_gas_is_elf = yes \ - && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 16 \) \* 1000 + 0` - then gcc_cv_as_comdat_group=yes -fi - elif test x$gcc_cv_as != x; then - echo '.section .text,"axG",@progbits,.foo,comdat' > conftest.s - if { ac_try='$gcc_cv_as --fatal-warnings -o conftest.o conftest.s >&5' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } - then - gcc_cv_as_comdat_group=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_as_comdat_group" >&5 -echo "${ECHO_T}$gcc_cv_as_comdat_group" >&6 - -if test $gcc_cv_as_comdat_group = yes; then - gcc_cv_as_comdat_group_percent=no -else - echo "$as_me:$LINENO: checking assembler for COMDAT group support" >&5 -echo $ECHO_N "checking assembler for COMDAT group support... $ECHO_C" >&6 -if test "${gcc_cv_as_comdat_group_percent+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_as_comdat_group_percent=no - if test $in_tree_gas = yes; then - if test $in_tree_gas_is_elf = yes \ - && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 16 \) \* 1000 + 0` - then gcc_cv_as_comdat_group_percent=yes -fi - elif test x$gcc_cv_as != x; then - echo '.section .text,"axG",%progbits,.foo,comdat' > conftest.s - if { ac_try='$gcc_cv_as --fatal-warnings -o conftest.o conftest.s >&5' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } - then - gcc_cv_as_comdat_group_percent=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_as_comdat_group_percent" >&5 -echo "${ECHO_T}$gcc_cv_as_comdat_group_percent" >&6 - -fi -if test $in_tree_ld != yes && test x"$ld_vers" != x; then - comdat_group=yes - if test 0"$ld_date" -lt 20050308; then - if test -n "$ld_date"; then - # If there was date string, but was earlier than 2005-03-08, fail - comdat_group=no - elif test "$ld_vers_major" -lt 2; then - comdat_group=no - elif test "$ld_vers_major" -eq 2 -a "$ld_vers_minor" -lt 16; then - comdat_group=no - fi - fi -else - # assume linkers other than GNU ld don't support COMDAT group - comdat_group=no -fi -if test $comdat_group = no; then - gcc_cv_as_comdat_group=no - gcc_cv_as_comdat_group_percent=no -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_COMDAT_GROUP `if test $gcc_cv_as_comdat_group = yes || test $gcc_cv_as_comdat_group_percent = yes; then echo 1; else echo 0; fi` -_ACEOF - - # Thread-local storage - the check is heavily parametrized. conftest_s= tls_first_major= @@ -14346,57 +10770,6 @@ foo: .long 25 tls_first_minor=13 tls_as_opt=--fatal-warnings ;; - frv*-*-*) - conftest_s=' - .section ".tdata","awT",@progbits -x: .long 25 - .text - call #gettlsoff(x)' - tls_first_major=2 - tls_first_minor=14 - ;; - hppa*-*-linux*) - conftest_s=' -t1: .reg %r20 -t2: .reg %r21 -gp: .reg %r19 - .section ".tdata","awT",@progbits -foo: .long 25 - .text - .align 4 - addil LT%foo-$tls_gdidx$,gp - ldo RT%foo-$tls_gdidx$(%r1),%arg0 - b __tls_get_addr - nop - addil LT%foo-$tls_ldidx$,gp - b __tls_get_addr - ldo RT%foo-$tls_ldidx$(%r1),%arg0 - addil LR%foo-$tls_dtpoff$,%ret0 - ldo RR%foo-$tls_dtpoff$(%r1),%t1 - mfctl %cr27,%t1 - addil LT%foo-$tls_ieoff$,gp - ldw RT%foo-$tls_ieoff$(%r1),%t2 - add %t1,%t2,%t3 - mfctl %cr27,%t1 - addil LR%foo-$tls_leoff$,%t1 - ldo RR%foo-$tls_leoff$(%r1),%t2' - tls_first_major=2 - tls_first_minor=15 - tls_as_opt=--fatal-warnings - ;; - arm*-*-*) - conftest_s=' - .section ".tdata","awT",%progbits -foo: .long 25 - .text -.word foo(gottpoff) -.word foo(tpoff) -.word foo(tlsgd) -.word foo(tlsldm) -.word foo(tlsldo)' - tls_first_major=2 - tls_first_minor=17 - ;; i[34567]86-*-*) conftest_s=' .section ".tdata","awT",@progbits @@ -14450,23 +10823,6 @@ foo: data8 25 tls_first_minor=13 tls_as_opt=--fatal-warnings ;; - mips*-*-*) - conftest_s=' - .section .tdata,"awT",@progbits -x: - .word 2 - .text - addiu $4, $28, %tlsgd(x) - addiu $4, $28, %tlsldm(x) - lui $4, %dtprel_hi(x) - addiu $4, $4, %dtprel_lo(x) - lw $4, %gottprel(x)($28) - lui $4, %tprel_hi(x) - addiu $4, $4, %tprel_lo(x)' - tls_first_major=2 - tls_first_minor=16 - tls_as_opt='-32 --fatal-warnings' - ;; powerpc-*-*) conftest_s=' .section ".tdata","awT",@progbits @@ -14580,15 +10936,6 @@ foo: .long 25 ;; sparc*-*-*) case "$target" in - sparc*-sun-solaris2.[56789]*) - # TLS was introduced in the Solaris 9 4/04 release but - # we do not enable it by default on Solaris 9 either. - if test "x$enable_tls" = xyes ; then - on_solaris=yes - else - enable_tls=no; - fi - ;; sparc*-sun-solaris2.*) on_solaris=yes ;; @@ -14650,12 +10997,7 @@ foo: .long 25 fi ;; esac -set_have_as_tls=no -if test "x$enable_tls" = xno ; then - : # TLS explicitly disabled. -elif test "x$enable_tls" = xyes ; then - set_have_as_tls=yes # TLS explicitly enabled. -elif test -z "$tls_first_major"; then +if test -z "$tls_first_major"; then : # If we don't have a check, assume no support. else echo "$as_me:$LINENO: checking assembler for thread-local storage support" >&5 @@ -14688,67 +11030,15 @@ fi echo "$as_me:$LINENO: result: $gcc_cv_as_tls" >&5 echo "${ECHO_T}$gcc_cv_as_tls" >&6 if test $gcc_cv_as_tls = yes; then - set_have_as_tls=yes -fi -fi -if test $set_have_as_tls = yes ; then cat >>confdefs.h <<\_ACEOF #define HAVE_AS_TLS 1 _ACEOF fi - -# Target-specific assembler checks. - -echo "$as_me:$LINENO: checking linker -Bstatic/-Bdynamic option" >&5 -echo $ECHO_N "checking linker -Bstatic/-Bdynamic option... $ECHO_C" >&6 -gcc_cv_ld_static_dynamic=no -if test $in_tree_ld = yes ; then - if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 10; then - gcc_cv_ld_static_dynamic=yes - fi -elif test x$gcc_cv_ld != x; then - # Check if linker supports -Bstatic/-Bdynamic option - if $gcc_cv_ld --help 2>/dev/null | grep -- -Bstatic > /dev/null \ - && $gcc_cv_ld --help 2>/dev/null | grep -- -Bdynamic > /dev/null; then - gcc_cv_ld_static_dynamic=yes - fi -fi -if test x"$gcc_cv_ld_static_dynamic" = xyes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LD_STATIC_DYNAMIC 1 -_ACEOF - fi -echo "$as_me:$LINENO: result: $gcc_cv_ld_static_dynamic" >&5 -echo "${ECHO_T}$gcc_cv_ld_static_dynamic" >&6 - -if test x"$demangler_in_ld" = xyes; then - echo "$as_me:$LINENO: checking linker --demangle support" >&5 -echo $ECHO_N "checking linker --demangle support... $ECHO_C" >&6 - gcc_cv_ld_demangle=no - if test $in_tree_ld = yes; then - if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then \ - gcc_cv_ld_demangle=yes - fi - elif test x$gcc_cv_ld != x -a x"$gnu_ld" = xyes; then - # Check if the GNU linker supports --demangle option - if $gcc_cv_ld --help 2>/dev/null | grep no-demangle > /dev/null; then - gcc_cv_ld_demangle=yes - fi - fi - if test x"$gcc_cv_ld_demangle" = xyes; then -cat >>confdefs.h <<\_ACEOF -#define HAVE_LD_DEMANGLE 1 -_ACEOF - - fi - echo "$as_me:$LINENO: result: $gcc_cv_ld_demangle" >&5 -echo "${ECHO_T}$gcc_cv_ld_demangle" >&6 -fi +# Target-specific assembler checks. case "$target" in # All TARGET_ABI_OSF targets. @@ -15085,55 +11375,6 @@ fi ;; i[34567]86-*-* | x86_64-*-*) - case $target_os in - cygwin* | pe | mingw32*) - # Used for DWARF 2 in PE - echo "$as_me:$LINENO: checking assembler for .secrel32 relocs" >&5 -echo $ECHO_N "checking assembler for .secrel32 relocs... $ECHO_C" >&6 -if test "${gcc_cv_as_ix86_pe_secrel32+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_as_ix86_pe_secrel32=no - if test $in_tree_gas = yes; then - if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 15 \) \* 1000 + 91` - then gcc_cv_as_ix86_pe_secrel32=yes -fi - elif test x$gcc_cv_as != x; then - echo '.text -foo: nop -.data - .secrel32 foo' > conftest.s - if { ac_try='$gcc_cv_as -o conftest.o conftest.s >&5' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } - then - if test x$gcc_cv_ld != x \ - && $gcc_cv_ld -o conftest conftest.o > /dev/null 2>&1; then - gcc_cv_as_ix86_pe_secrel32=yes - fi - rm -f conftest - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_as_ix86_pe_secrel32" >&5 -echo "${ECHO_T}$gcc_cv_as_ix86_pe_secrel32" >&6 -if test $gcc_cv_as_ix86_pe_secrel32 = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_GAS_PE_SECREL32_RELOC 1 -_ACEOF - -fi - ;; - esac - echo "$as_me:$LINENO: checking assembler for filds and fists mnemonics" >&5 echo $ECHO_N "checking assembler for filds and fists mnemonics... $ECHO_C" >&6 if test "${gcc_cv_as_ix86_filds_fists+set}" = set; then @@ -15204,39 +11445,6 @@ _ACEOF fi - echo "$as_me:$LINENO: checking assembler for ffreep mnemonic" >&5 -echo $ECHO_N "checking assembler for ffreep mnemonic... $ECHO_C" >&6 -if test "${gcc_cv_as_ix86_ffreep+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_as_ix86_ffreep=no - if test x$gcc_cv_as != x; then - echo 'ffreep %st(1)' > conftest.s - if { ac_try='$gcc_cv_as -o conftest.o conftest.s >&5' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } - then - gcc_cv_as_ix86_ffreep=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_as_ix86_ffreep" >&5 -echo "${ECHO_T}$gcc_cv_as_ix86_ffreep" >&6 -if test $gcc_cv_as_ix86_ffreep = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_AS_IX86_FFREEP 1 -_ACEOF - -fi - # This one is used unconditionally by i386.[ch]; it is to be defined # to 1 if the feature is present, 0 otherwise. echo "$as_me:$LINENO: checking assembler for GOTOFF in data" >&5 @@ -15325,45 +11533,11 @@ fi powerpc*-*-*) case $target in - *-*-aix*) conftest_s=' .machine "pwr5" - .csect .text[PR] + *-*-aix*) conftest_s=' .csect .text[PR] mfcr 3,128';; - *-*-darwin*) - echo "$as_me:$LINENO: checking assembler for .machine directive support" >&5 -echo $ECHO_N "checking assembler for .machine directive support... $ECHO_C" >&6 -if test "${gcc_cv_as_machine_directive+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_as_machine_directive=no - if test x$gcc_cv_as != x; then - echo ' .machine ppc7400' > conftest.s - if { ac_try='$gcc_cv_as -o conftest.o conftest.s >&5' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } - then - gcc_cv_as_machine_directive=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_as_machine_directive" >&5 -echo "${ECHO_T}$gcc_cv_as_machine_directive" >&6 - - if test x$gcc_cv_as_machine_directive != xyes; then - echo "*** This target requires an assembler supporting \".machine\"" >&2 - echo you can get it from: ftp://gcc.gnu.org/pub/gcc/infrastructure/cctools-528.5.dmg >&2 - test x$build = x$target && exit 1 - fi - conftest_s=' .text + *-*-darwin*) conftest_s=' .text mfcr r3,128';; - *) conftest_s=' .machine power4 - .text + *) conftest_s=' .text mfcr 3,128';; esac @@ -15403,148 +11577,6 @@ cat >>confdefs.h <<\_ACEOF _ACEOF fi - - case $target in - *-*-aix*) conftest_s=' .machine "pwr5" - .csect .text[PR] - popcntb 3,3';; - *) conftest_s=' .machine power5 - .text - popcntb 3,3';; - esac - - echo "$as_me:$LINENO: checking assembler for popcntb support" >&5 -echo $ECHO_N "checking assembler for popcntb support... $ECHO_C" >&6 -if test "${gcc_cv_as_powerpc_popcntb+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_as_powerpc_popcntb=no - if test $in_tree_gas = yes; then - if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 17 \) \* 1000 + 0` - then gcc_cv_as_powerpc_popcntb=yes -fi - elif test x$gcc_cv_as != x; then - echo "$conftest_s" > conftest.s - if { ac_try='$gcc_cv_as -o conftest.o conftest.s >&5' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } - then - gcc_cv_as_powerpc_popcntb=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_as_powerpc_popcntb" >&5 -echo "${ECHO_T}$gcc_cv_as_powerpc_popcntb" >&6 -if test $gcc_cv_as_powerpc_popcntb = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_AS_POPCNTB 1 -_ACEOF - -fi - - case $target in - *-*-aix*) conftest_s=' .machine "pwr5x" - .csect .text[PR] - frin 1,1';; - *) conftest_s=' .machine power5 - .text - frin 1,1';; - esac - - echo "$as_me:$LINENO: checking assembler for fp round support" >&5 -echo $ECHO_N "checking assembler for fp round support... $ECHO_C" >&6 -if test "${gcc_cv_as_powerpc_fprnd+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_as_powerpc_fprnd=no - if test $in_tree_gas = yes; then - if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 17 \) \* 1000 + 0` - then gcc_cv_as_powerpc_fprnd=yes -fi - elif test x$gcc_cv_as != x; then - echo "$conftest_s" > conftest.s - if { ac_try='$gcc_cv_as -o conftest.o conftest.s >&5' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } - then - gcc_cv_as_powerpc_fprnd=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_as_powerpc_fprnd" >&5 -echo "${ECHO_T}$gcc_cv_as_powerpc_fprnd" >&6 -if test $gcc_cv_as_powerpc_fprnd = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_AS_FPRND 1 -_ACEOF - -fi - - case $target in - *-*-aix*) conftest_s=' .csect .text[PR] -LCF..0: - addis 11,30,_GLOBAL_OFFSET_TABLE_-LCF..0@ha';; - *-*-darwin*) - conftest_s=' .text -LCF0: - addis r11,r30,_GLOBAL_OFFSET_TABLE_-LCF0@ha';; - *) conftest_s=' .text -.LCF0: - addis 11,30,_GLOBAL_OFFSET_TABLE_-.LCF0@ha';; - esac - - echo "$as_me:$LINENO: checking assembler for rel16 relocs" >&5 -echo $ECHO_N "checking assembler for rel16 relocs... $ECHO_C" >&6 -if test "${gcc_cv_as_powerpc_rel16+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_as_powerpc_rel16=no - if test $in_tree_gas = yes; then - if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 17 \) \* 1000 + 0` - then gcc_cv_as_powerpc_rel16=yes -fi - elif test x$gcc_cv_as != x; then - echo "$conftest_s" > conftest.s - if { ac_try='$gcc_cv_as -a32 -o conftest.o conftest.s >&5' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } - then - gcc_cv_as_powerpc_rel16=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_as_powerpc_rel16" >&5 -echo "${ECHO_T}$gcc_cv_as_powerpc_rel16" >&6 -if test $gcc_cv_as_powerpc_rel16 = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_AS_REL16 1 -_ACEOF - -fi ;; mips*-*-*) @@ -15583,26 +11615,9 @@ if test $gcc_cv_as_mips_explicit_relocs = yes; then else target_cpu_default="($target_cpu_default)|MASK_EXPLICIT_RELOCS" fi fi - ;; -esac -# Mips and HP-UX need the GNU assembler. -# Linux on IA64 might be able to use the Intel assembler. - -case "$target" in - mips*-*-* | *-*-hpux* ) - if test x$gas_flag = xyes \ - || test x"$host" != x"$build" \ - || test ! -x "$gcc_cv_as" \ - || "$gcc_cv_as" -v < /dev/null 2>&1 | grep GNU > /dev/null; then - : - else - echo "*** This configuration requires the GNU assembler" >&2 - exit 1 - fi ;; esac - # ??? Not all targets support dwarf2 debug_line, even within a version # of gas. Moreover, we need to emit a valid instruction to trigger any # info to the output file. So, as supported targets are added to gas 2.11, @@ -15612,7 +11627,7 @@ esac case "$target" in i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* \ | x86_64*-*-* | hppa*-*-* | arm*-*-* | strongarm*-*-* | xscale*-*-* \ - | xstormy16*-*-* | cris-*-* | xtensa-*-* | bfin-*-* | score*-*-*) + | xstormy16*-*-* | cris-*-* | xtensa-*-*) insn="nop" ;; ia64*-*-* | s390*-*-*) @@ -15647,9 +11662,8 @@ fi echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } then - if test x$gcc_cv_objdump != x \ - && $gcc_cv_objdump -h conftest.o 2> /dev/null \ - | grep debug_line > /dev/null 2>&1; then + # ??? This fails with non-gnu grep. Maybe use objdump? + if grep debug_line conftest.o > /dev/null 2>&1; then gcc_cv_as_dwarf2_debug_line=yes fi else @@ -15847,7 +11861,6 @@ elif test x$gcc_cv_ld != x; then gcc_cv_ld_eh_frame_hdr=yes fi fi - if test x"$gcc_cv_ld_eh_frame_hdr" = xyes; then cat >>confdefs.h <<\_ACEOF @@ -15882,115 +11895,63 @@ fi echo "$as_me:$LINENO: result: $gcc_cv_ld_pie" >&5 echo "${ECHO_T}$gcc_cv_ld_pie" >&6 -# -------- -# UNSORTED -# -------- - -echo "$as_me:$LINENO: checking linker --as-needed support" >&5 -echo $ECHO_N "checking linker --as-needed support... $ECHO_C" >&6 -if test "${gcc_cv_ld_as_needed+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_ld_as_needed=no +echo "$as_me:$LINENO: checking linker -Bstatic/-Bdynamic option" >&5 +echo $ECHO_N "checking linker -Bstatic/-Bdynamic option... $ECHO_C" >&6 +gcc_cv_ld_static_dynamic=no if test $in_tree_ld = yes ; then - if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 16 -o "$gcc_cv_gld_major_version" -gt 2 \ - && test $in_tree_ld_is_elf = yes; then - gcc_cv_ld_as_needed=yes + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 10; then + gcc_cv_ld_static_dynamic=yes fi elif test x$gcc_cv_ld != x; then - # Check if linker supports --as-needed and --no-as-needed options - if $gcc_cv_ld --help 2>/dev/null | grep as-needed > /dev/null; then - gcc_cv_ld_as_needed=yes + # Check if linker supports -Bstatic/-Bdynamic option + if $gcc_cv_ld --help 2>/dev/null | grep -- -Bstatic > /dev/null \ + && $gcc_cv_ld --help 2>/dev/null | grep -- -Bdynamic > /dev/null; then + gcc_cv_ld_static_dynamic=yes fi fi - -fi -echo "$as_me:$LINENO: result: $gcc_cv_ld_as_needed" >&5 -echo "${ECHO_T}$gcc_cv_ld_as_needed" >&6 -if test x"$gcc_cv_ld_as_needed" = xyes; then +if test x"$gcc_cv_ld_static_dynamic" = xyes; then cat >>confdefs.h <<\_ACEOF -#define HAVE_LD_AS_NEEDED 1 +#define HAVE_LD_STATIC_DYNAMIC 1 _ACEOF fi +echo "$as_me:$LINENO: result: $gcc_cv_ld_static_dynamic" >&5 +echo "${ECHO_T}$gcc_cv_ld_static_dynamic" >&6 -case "$target:$tm_file" in - powerpc64*-*-linux* | powerpc*-*-linux*rs6000/biarch64.h*) - echo "$as_me:$LINENO: checking linker support for omitting dot symbols" >&5 -echo $ECHO_N "checking linker support for omitting dot symbols... $ECHO_C" >&6 -if test "${gcc_cv_ld_no_dot_syms+set}" = set; then +case "$target" in + *-*-linux*) + echo "$as_me:$LINENO: checking linker --as-needed support" >&5 +echo $ECHO_N "checking linker --as-needed support... $ECHO_C" >&6 +if test "${gcc_cv_ld_as_needed+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - gcc_cv_ld_no_dot_syms=no + gcc_cv_ld_as_needed=no if test $in_tree_ld = yes ; then - if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 16 -o "$gcc_cv_gld_major_version" -gt 2; then - gcc_cv_ld_no_dot_syms=yes + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 16 -o "$gcc_cv_gld_major_version" -gt 2 \ + && test $in_tree_ld_is_elf = yes; then + gcc_cv_ld_as_needed=yes fi - elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x ; then - cat > conftest1.s <<EOF - .text - bl .foo -EOF - cat > conftest2.s <<EOF - .section ".opd","aw" - .align 3 - .globl foo - .type foo,@function -foo: - .quad .LEfoo,.TOC.@tocbase,0 - .text -.LEfoo: - blr - .size foo,.-.LEfoo -EOF - if $gcc_cv_as -a64 -o conftest1.o conftest1.s > /dev/null 2>&1 \ - && $gcc_cv_as -a64 -o conftest2.o conftest2.s > /dev/null 2>&1 \ - && $gcc_cv_ld -melf64ppc -o conftest conftest1.o conftest2.o > /dev/null 2>&1; then - gcc_cv_ld_no_dot_syms=yes + elif test x$gcc_cv_ld != x; then + # Check if linker supports --as-needed and --no-as-needed options + if $gcc_cv_ld --help 2>/dev/null | grep as-needed > /dev/null; then + gcc_cv_ld_as_needed=yes fi - rm -f conftest conftest1.o conftest2.o conftest1.s conftest2.s fi fi -echo "$as_me:$LINENO: result: $gcc_cv_ld_no_dot_syms" >&5 -echo "${ECHO_T}$gcc_cv_ld_no_dot_syms" >&6 - if test x"$gcc_cv_ld_no_dot_syms" = xyes; then +echo "$as_me:$LINENO: result: $gcc_cv_ld_as_needed" >&5 +echo "${ECHO_T}$gcc_cv_ld_as_needed" >&6 + if test x"$gcc_cv_ld_as_needed" = xyes; then cat >>confdefs.h <<\_ACEOF -#define HAVE_LD_NO_DOT_SYMS 1 +#define HAVE_LD_AS_NEEDED 1 _ACEOF fi ;; esac -echo "$as_me:$LINENO: checking linker --sysroot support" >&5 -echo $ECHO_N "checking linker --sysroot support... $ECHO_C" >&6 -if test "${gcc_cv_ld_sysroot+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_ld_sysroot=no - if test $in_tree_ld = yes ; then - if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 16 -o "$gcc_cv_gld_major_version" -gt 2 ; then - gcc_cv_ld_sysroot=yes - fi - elif test x$gcc_cv_ld != x; then - if $gcc_cv_ld --help 2>/dev/null | grep sysroot > /dev/null; then - gcc_cv_ld_sysroot=yes - fi - fi -fi -echo "$as_me:$LINENO: result: $gcc_cv_ld_sysroot" >&5 -echo "${ECHO_T}$gcc_cv_ld_sysroot" >&6 -if test x"$gcc_cv_ld_sysroot" = xyes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LD_SYSROOT 1 -_ACEOF - -fi - if test x$with_sysroot = x && test x$host = x$target \ && test "$prefix" != "/usr" && test "x$prefix" != "x$local_prefix" ; then @@ -16000,112 +11961,152 @@ _ACEOF fi -# Test for stack protector support in target C library. -case "$target" in - *-*-linux*) - echo "$as_me:$LINENO: checking __stack_chk_fail in target GNU C library" >&5 -echo $ECHO_N "checking __stack_chk_fail in target GNU C library... $ECHO_C" >&6 -if test "${gcc_cv_libc_provides_ssp+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - gcc_cv_libc_provides_ssp=no - if test x$host != x$target || test "x$TARGET_SYSTEM_ROOT" != x; then - if test "x$with_sysroot" = x; then - glibc_header_dir="${exec_prefix}/${target_noncanonical}/sys-include" - elif test "x$with_sysroot" = xyes; then - glibc_header_dir="${exec_prefix}/${target_noncanonical}/sys-root/usr/include" +# Figure out what language subdirectories are present. +# Look if the user specified --enable-languages="..."; if not, use +# the environment variable $LANGUAGES if defined. $LANGUAGES might +# go away some day. +# NB: embedded tabs in this IF block -- do not untabify +if test x"${enable_languages+set}" != xset; then + if test x"${LANGUAGES+set}" = xset; then + enable_languages="${LANGUAGES}" + { echo "$as_me:$LINENO: WARNING: setting LANGUAGES is deprecated, use --enable-languages instead" >&5 +echo "$as_me: WARNING: setting LANGUAGES is deprecated, use --enable-languages instead" >&2;} + else - glibc_header_dir="${with_sysroot}/usr/include" + enable_languages=all fi - else - glibc_header_dir=/usr/include - fi - # glibc 2.4 and later provides __stack_chk_fail and - # either __stack_chk_guard, or TLS access to stack guard canary. - if test -f $glibc_header_dir/features.h \ - && $EGREP '^[ ]*#[ ]*define[ ]+__GNU_LIBRARY__[ ]+([1-9][0-9]|[6-9])' \ - $glibc_header_dir/features.h > /dev/null; then - if $EGREP '^[ ]*#[ ]*define[ ]+__GLIBC__[ ]+([1-9][0-9]|[3-9])' \ - $glibc_header_dir/features.h > /dev/null; then - gcc_cv_libc_provides_ssp=yes - elif $EGREP '^[ ]*#[ ]*define[ ]+__GLIBC__[ ]+2' \ - $glibc_header_dir/features.h > /dev/null \ - && $EGREP '^[ ]*#[ ]*define[ ]+__GLIBC_MINOR__[ ]+([1-9][0-9]|[4-9])' \ - $glibc_header_dir/features.h > /dev/null; then - gcc_cv_libc_provides_ssp=yes +else + if test x"${enable_languages}" = x \ + || test x"${enable_languages}" = xyes; + then + { { echo "$as_me:$LINENO: error: --enable-languages needs at least one language argument" >&5 +echo "$as_me: error: --enable-languages needs at least one language argument" >&2;} + { (exit 1); exit 1; }; } fi - fi fi -echo "$as_me:$LINENO: result: $gcc_cv_libc_provides_ssp" >&5 -echo "${ECHO_T}$gcc_cv_libc_provides_ssp" >&6 ;; - *) gcc_cv_libc_provides_ssp=no ;; -esac -if test x$gcc_cv_libc_provides_ssp = xyes; then - -cat >>confdefs.h <<\_ACEOF -#define TARGET_LIBC_PROVIDES_SSP 1 -_ACEOF +enable_languages=`echo "${enable_languages}" | sed -e 's/[ ,][ ,]*/,/g' -e 's/,$//'` -fi +# First scan to see if an enabled language requires some other language. +# We assume that a given config-lang.in will list all the language +# front ends it requires, even if some are required indirectly. +for lang in ${srcdir}/*/config-lang.in +do + case $lang in + # The odd quoting in the next line works around + # an apparent bug in bash 1.12 on linux. + ${srcdir}/[*]/config-lang.in) + ;; + *) + lang_alias=`sed -n -e 's,^language=['"'"'"'"]\(.*\)["'"'"'"'].*$,\1,p' -e 's,^language=\([^ ]*\).*$,\1,p' $lang` + this_lang_requires=`sed -n -e 's,^lang_requires=['"'"'"'"]\(.*\)["'"'"'"'].*$,\1,p' -e 's,^lang_requires=\([^ ]*\).*$,\1,p' $lang` + for other in $this_lang_requires + do + case ,${enable_languages}, in + *,$other,*) + ;; + *,all,*) + ;; + *,$lang_alias,*) + enable_languages="$enable_languages,$other" + ;; + esac + done + ;; + esac +done -# Check if TFmode long double should be used by default or not. -# Some glibc targets used DFmode long double, but with glibc 2.4 -# and later they can use TFmode. -case "$target" in - powerpc*-*-*gnu* | \ - sparc*-*-linux* | \ - s390*-*-linux* | \ - alpha*-*-linux*) - -# Check whether --with-long-double-128 or --without-long-double-128 was given. -if test "${with_long_double_128+set}" = set; then - withval="$with_long_double_128" - gcc_cv_target_ldbl128="$with_long_double_128" -else - gcc_cv_target_ldbl128=no - if test x$host != x$target || test "x$TARGET_SYSTEM_ROOT" != x; then - if test "x$with_sysroot" = x; then - glibc_header_dir="${exec_prefix}/${target_noncanonical}/sys-include" - elif test "x$with_sysroot" = xyes; then - glibc_header_dir="${exec_prefix}/${target_noncanonical}/sys-root/usr/include" - else - glibc_header_dir="${with_sysroot}/usr/include" - fi - else - glibc_header_dir=/usr/include - fi - grep '^[ ]*#[ ]*define[ ][ ]*__LONG_DOUBLE_MATH_OPTIONAL' \ - $glibc_header_dir/bits/wordsize.h > /dev/null 2>&1 \ - && gcc_cv_target_ldbl128=yes +expected_languages=`echo ,${enable_languages}, | sed -e 's:,: :g' -e 's: *: :g' -e 's: *: :g' -e 's:^ ::' -e 's: $::'` +found_languages= +subdirs= +for lang in ${srcdir}/*/config-lang.in +do + case $lang in + # The odd quoting in the next line works around + # an apparent bug in bash 1.12 on linux. + ${srcdir}/[*]/config-lang.in) ;; + *) + lang_alias=`sed -n -e 's,^language=['"'"'"'"]\(.*\)["'"'"'"'].*$,\1,p' -e 's,^language=\([^ ]*\).*$,\1,p' $lang` + this_lang_libs=`sed -n -e 's,^target_libs=['"'"'"'"]\(.*\)["'"'"'"'].*$,\1,p' -e 's,^target_libs=\([^ ]*\).*$,\1,p' $lang` + build_by_default=`sed -n -e 's,^build_by_default=['"'"'"'"]\(.*\)["'"'"'"'].*$,\1,p' -e 's,^build_by_default=\([^ ]*\).*$,\1,p' $lang` + if test "x$lang_alias" = x + then + echo "$lang doesn't set \$language." 1>&2 + exit 1 + fi + case ${build_by_default},${enable_languages}, in + *,$lang_alias,*) add_this_lang=yes ;; + no,*) add_this_lang=no ;; + *,all,*) add_this_lang=yes ;; + *) add_this_lang=no ;; + esac + found_languages="${found_languages} ${lang_alias}" + if test x"${add_this_lang}" = xyes; then + case $lang in + ${srcdir}/ada/config-lang.in) + if test x$have_gnat = xyes ; then + subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([^/]*\)/config-lang.in$,\1,'`" + fi + ;; + *) + subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([^/]*\)/config-lang.in$,\1,'`" + ;; + esac + fi + ;; + esac +done -fi; - ;; -esac -if test x$gcc_cv_target_ldbl128 = xyes; then +missing_languages= +for expected_language in ${expected_languages} .. +do + if test "${expected_language}" != ..; then + missing_language="${expected_language}" + if test "${expected_language}" = "c" \ + || test "${expected_language}" = "all"; then + missing_language= + fi + for found_language in ${found_languages} .. + do + if test "${found_language}" != ..; then + if test "${expected_language}" = "${found_language}"; then + missing_language= + fi + fi + done + if test "x${missing_language}" != x; then + missing_languages="${missing_languages} ${missing_language}" + fi + fi +done -cat >>confdefs.h <<\_ACEOF -#define TARGET_DEFAULT_LONG_DOUBLE_128 1 -_ACEOF +if test "x$missing_languages" != x; then + { { echo "$as_me:$LINENO: error: +The following requested languages were not found:${missing_languages} +The following languages were available: c${found_languages}" >&5 +echo "$as_me: error: +The following requested languages were not found:${missing_languages} +The following languages were available: c${found_languages}" >&2;} + { (exit 1); exit 1; }; } +fi +# Make gthr-default.h if we have a thread file. +gthread_flags= +if test $thread_file != single; then + rm -f gthr-default.h + echo "#include \"gthr-${thread_file}.h\"" > gthr-default.h + gthread_flags=-DHAVE_GTHR_DEFAULT fi + # Find out what GC implementation we want, or may, use. # Check whether --with-gc or --without-gc was given. if test "${with_gc+set}" = set; then withval="$with_gc" case "$withval" in - page) + simple | page | zone) GGC=ggc-$withval ;; - zone) - GGC=ggc-$withval - -cat >>confdefs.h <<\_ACEOF -#define GGC_ZONE 1 -_ACEOF - - ;; *) { { echo "$as_me:$LINENO: error: $withval is an invalid option to --with-gc" >&5 echo "$as_me: error: $withval is an invalid option to --with-gc" >&2;} @@ -16152,24 +12153,32 @@ else MAINT='#' fi -# -------------- -# Language hooks -# -------------- - # Make empty files to contain the specs and options for each language. # Then add #include lines to for a compiler that has specs and/or options. -subdirs= lang_opt_files= lang_specs_files= lang_tree_files= +for subdir in . $subdirs +do + if test -f $srcdir/$subdir/lang.opt; then + lang_opt_files="$lang_opt_files $srcdir/$subdir/lang.opt" + fi + if test -f $srcdir/$subdir/lang-specs.h; then + lang_specs_files="$lang_specs_files $srcdir/$subdir/lang-specs.h" + fi + if test -f $srcdir/$subdir/$subdir-tree.def; then + lang_tree_files="$lang_tree_files $srcdir/$subdir/$subdir-tree.def" + fi +done + # These (without "all_") are set in each config-lang.in. # `language' must be a single word so is spelled singularly. all_languages= all_boot_languages= all_compilers= all_stagestuff= -all_outputs='Makefile gccbug mklibgcc libada-mk' +all_outputs='Makefile fixinc/Makefile gccbug mklibgcc mkheaders' # List of language makefile fragments. all_lang_makefrags= # List of language subdirectory makefiles. Deprecated. @@ -16180,10 +12189,6 @@ all_gtfiles="$target_gtfiles" all_gtfiles_files_langs= all_gtfiles_files_files= -# These are the languages that are set in --enable-languages, -# and are available in the GCC tree. -all_selected_languages= - # Add the language fragments. # Languages are added via two mechanisms. Some information must be # recorded in makefile variables, these are defined in config-lang.in. @@ -16193,122 +12198,77 @@ all_selected_languages= language_hooks="Make-hooks" -for lang in ${srcdir}/*/config-lang.in +for s in $subdirs do - test "$lang" = "${srcdir}/*/config-lang.in" && continue - - lang_alias=`sed -n -e 's,^language=['"'"'"'"]\(.*\)["'"'"'"'].*$,\1,p' -e 's,^language=\([^ ]*\).*$,\1,p' $lang` - if test "x$lang_alias" = x - then - echo "$lang doesn't set \$language." 1>&2 - exit 1 - fi - subdir="`echo $lang | sed -e 's,^.*/\([^/]*\)/config-lang.in$,\1,'`" - subdirs="$subdirs $subdir" - case ",$enable_languages," in - *,$lang_alias,*) - all_selected_languages="$all_selected_languages $lang_alias" - if test -f $srcdir/$subdir/lang-specs.h; then - lang_specs_files="$lang_specs_files $srcdir/$subdir/lang-specs.h" - fi - ;; - esac - - language= - boot_language= - compilers= - stagestuff= - outputs= - gtfiles= - subdir_requires= - . ${srcdir}/$subdir/config-lang.in - if test "x$language" = x - then - echo "${srcdir}/$subdir/config-lang.in doesn't set \$language." 1>&2 - exit 1 - fi - - ok=: - case ",$enable_languages," in - *,$lang_alias,*) ;; - *) - for i in $subdir_requires; do - test -f "${srcdir}/$i/config-lang.in" && continue - ok=false - break - done - ;; - esac - $ok || continue - - all_lang_makefrags="$all_lang_makefrags \$(srcdir)/$subdir/Make-lang.in" - if test -f $srcdir/$subdir/lang.opt; then - lang_opt_files="$lang_opt_files $srcdir/$subdir/lang.opt" - fi - if test -f $srcdir/$subdir/$subdir-tree.def; then - lang_tree_files="$lang_tree_files $srcdir/$subdir/$subdir-tree.def" - fi - if test -f ${srcdir}/$subdir/Makefile.in - then all_lang_makefiles="$subdir/Makefile" - fi - all_languages="$all_languages $language" - if test "x$boot_language" = xyes - then - all_boot_languages="$all_boot_languages $language" - fi - all_compilers="$all_compilers $compilers" - all_stagestuff="$all_stagestuff $stagestuff" - all_outputs="$all_outputs $outputs" - all_gtfiles="$all_gtfiles $gtfiles" - for f in $gtfiles - do - all_gtfiles_files_langs="$all_gtfiles_files_langs ${subdir} " - all_gtfiles_files_files="$all_gtfiles_files_files ${f} " - done + language= + boot_language= + compilers= + stagestuff= + outputs= + gtfiles= + . ${srcdir}/$s/config-lang.in + if test "x$language" = x + then + echo "${srcdir}/$s/config-lang.in doesn't set \$language." 1>&2 + exit 1 + fi + all_lang_makefrags="$all_lang_makefrags \$(srcdir)/$s/Make-lang.in" + if test -f ${srcdir}/$s/Makefile.in + then all_lang_makefiles="$s/Makefile" + fi + all_languages="$all_languages $language" + if test "x$boot_language" = xyes + then + all_boot_languages="$all_boot_languages $language" + fi + all_compilers="$all_compilers $compilers" + all_stagestuff="$all_stagestuff $stagestuff" + all_outputs="$all_outputs $outputs" + all_gtfiles="$all_gtfiles $gtfiles" + for f in $gtfiles + do + all_gtfiles_files_langs="$all_gtfiles_files_langs ${s} " + all_gtfiles_files_files="$all_gtfiles_files_files ${f} " + done done # Pick up gtfiles for c gtfiles= -subdir="c" +s="c" . ${srcdir}/c-config-lang.in all_gtfiles="$all_gtfiles $gtfiles" for f in $gtfiles do - all_gtfiles_files_langs="$all_gtfiles_files_langs ${subdir} " + all_gtfiles_files_langs="$all_gtfiles_files_langs ${s} " all_gtfiles_files_files="$all_gtfiles_files_files ${f} " done check_languages= -for language in $all_selected_languages +for language in $all_languages do - check_languages="$check_languages check-$language" + check_languages="$check_languages check-$language" done # We link each language in with a set of hooks, reached indirectly via -# lang.${target}. Only do so for selected languages. +# lang.${target}. rm -f Make-hooks touch Make-hooks -target_list="all.cross start.encap rest.encap tags \ - install-common install-man install-info dvi pdf html \ +target_list="all.build all.cross start.encap rest.encap tags \ + install-normal install-common install-man \ uninstall info man srcextra srcman srcinfo \ mostlyclean clean distclean maintainer-clean \ stage1 stage2 stage3 stage4 stageprofile stagefeedback" - for t in $target_list do x= - for lang in $all_selected_languages + for lang in $all_languages do - x="$x $lang.$t" + x="$x $lang.$t" done echo "lang.$t: $x" >> Make-hooks done -# -------- -# UNSORTED -# -------- - # Create .gdbinit. echo "dir ." > .gdbinit @@ -16389,37 +12349,17 @@ fi; objdir=`${PWDCMD-pwd}` +# Substitute configuration variables + -# Check whether --with-datarootdir or --without-datarootdir was given. -if test "${with_datarootdir+set}" = set; then - withval="$with_datarootdir" - datarootdir="\${prefix}/$with_datarootdir" -else - datarootdir='$(prefix)/share' -fi; -# Check whether --with-docdir or --without-docdir was given. -if test "${with_docdir+set}" = set; then - withval="$with_docdir" - docdir="\${prefix}/$with_docdir" -else - docdir='$(datarootdir)' -fi; -# Check whether --with-htmldir or --without-htmldir was given. -if test "${with_htmldir+set}" = set; then - withval="$with_htmldir" - htmldir="\${prefix}/$with_htmldir" -else - htmldir='$(docdir)' -fi; -# Substitute configuration variables @@ -16480,9 +12420,28 @@ fi; +if test x"$SET_GCC_LIB_PATH_CMD" != x; then + # SET_GCC_LIB_PATH_CMD is "XXX=path; export XXX;". It is expanded to + # + # eval "set_gcc_lib_path=XXX=path; export XXX;" + # + eval "set_gcc_lib_path=$SET_GCC_LIB_PATH_CMD" + # It will set set_gcc_lib_path to "export XXX=path" for GNU make. + set_gcc_lib_path="export $set_gcc_lib_path" +else + set_gcc_lib_path= +fi +# If it doesn't already exist, create document directory +echo "checking for the document directory." 1>&2 +if test -d doc ; then + true +else + mkdir doc +fi + # Echo link setup. if test x${build} = x${host} ; then if test x${host} = x${target} ; then @@ -16501,9 +12460,6 @@ else fi fi - - - # Configure the subdirectories # AC_CONFIG_SUBDIRS($subdirs) @@ -17038,6 +12994,8 @@ cat >>$CONFIG_STATUS <<_ACEOF # subdirs='$subdirs' +symbolic_link='$symbolic_link' + _ACEOF @@ -17148,8 +13106,6 @@ s,@target@,$target,;t t s,@target_cpu@,$target_cpu,;t t s,@target_vendor@,$target_vendor,;t t s,@target_os@,$target_os,;t t -s,@target_noncanonical@,$target_noncanonical,;t t -s,@build_libsubdir@,$build_libsubdir,;t t s,@build_subdir@,$build_subdir,;t t s,@host_subdir@,$host_subdir,;t t s,@target_subdir@,$target_subdir,;t t @@ -17164,34 +13120,29 @@ s,@OBJEXT@,$OBJEXT,;t t s,@NO_MINUS_C_MINUS_O@,$NO_MINUS_C_MINUS_O,;t t s,@OUTPUT_OPTION@,$OUTPUT_OPTION,;t t s,@CPP@,$CPP,;t t -s,@EGREP@,$EGREP,;t t +s,@GNATBIND@,$GNATBIND,;t t +s,@ac_ct_GNATBIND@,$ac_ct_GNATBIND,;t t s,@strict1_warn@,$strict1_warn,;t t -s,@cxx_compat_warn@,$cxx_compat_warn,;t t s,@warn_cflags@,$warn_cflags,;t t s,@WERROR@,$WERROR,;t t s,@nocommon_flag@,$nocommon_flag,;t t -s,@TREEBROWSER@,$TREEBROWSER,;t t +s,@EGREP@,$EGREP,;t t s,@valgrind_path@,$valgrind_path,;t t s,@valgrind_path_defines@,$valgrind_path_defines,;t t s,@valgrind_command@,$valgrind_command,;t t s,@coverage_flags@,$coverage_flags,;t t s,@enable_multilib@,$enable_multilib,;t t -s,@enable_decimal_float@,$enable_decimal_float,;t t s,@enable_shared@,$enable_shared,;t t s,@TARGET_SYSTEM_ROOT@,$TARGET_SYSTEM_ROOT,;t t s,@TARGET_SYSTEM_ROOT_DEFINE@,$TARGET_SYSTEM_ROOT_DEFINE,;t t s,@CROSS_SYSTEM_HEADER_DIR@,$CROSS_SYSTEM_HEADER_DIR,;t t s,@onestep@,$onestep,;t t -s,@datarootdir@,$datarootdir,;t t -s,@docdir@,$docdir,;t t -s,@htmldir@,$htmldir,;t t s,@SET_MAKE@,$SET_MAKE,;t t s,@AWK@,$AWK,;t t -s,@LN_S@,$LN_S,;t t s,@LN@,$LN,;t t +s,@LN_S@,$LN_S,;t t s,@RANLIB@,$RANLIB,;t t s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t -s,@ranlib_flags@,$ranlib_flags,;t t s,@INSTALL@,$INSTALL,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t @@ -17202,21 +13153,19 @@ s,@BUILD_INFO@,$BUILD_INFO,;t t s,@GENERATED_MANPAGES@,$GENERATED_MANPAGES,;t t s,@FLEX@,$FLEX,;t t s,@BISON@,$BISON,;t t -s,@NM@,$NM,;t t -s,@AR@,$AR,;t t s,@stage1_cflags@,$stage1_cflags,;t t s,@COLLECT2_LIBS@,$COLLECT2_LIBS,;t t s,@GNAT_LIBEXC@,$GNAT_LIBEXC,;t t s,@LDEXP_LIB@,$LDEXP_LIB,;t t s,@TARGET_GETGROUPS_T@,$TARGET_GETGROUPS_T,;t t s,@LIBICONV@,$LIBICONV,;t t -s,@LTLIBICONV@,$LTLIBICONV,;t t s,@LIBICONV_DEP@,$LIBICONV_DEP,;t t s,@manext@,$manext,;t t s,@objext@,$objext,;t t -s,@gthread_flags@,$gthread_flags,;t t s,@extra_modes_file@,$extra_modes_file,;t t -s,@extra_opt_files@,$extra_opt_files,;t t +s,@FORBUILD@,$FORBUILD,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t s,@USE_NLS@,$USE_NLS,;t t s,@LIBINTL@,$LIBINTL,;t t s,@LIBINTL_DEP@,$LIBINTL_DEP,;t t @@ -17225,28 +13174,18 @@ s,@XGETTEXT@,$XGETTEXT,;t t s,@GMSGFMT@,$GMSGFMT,;t t s,@POSUB@,$POSUB,;t t s,@CATALOGS@,$CATALOGS,;t t -s,@DATADIRNAME@,$DATADIRNAME,;t t -s,@INSTOBJEXT@,$INSTOBJEXT,;t t -s,@GENCAT@,$GENCAT,;t t -s,@CATOBJEXT@,$CATOBJEXT,;t t -s,@host_cc_for_libada@,$host_cc_for_libada,;t t s,@CROSS@,$CROSS,;t t s,@ALL@,$ALL,;t t s,@SYSTEM_HEADER_DIR@,$SYSTEM_HEADER_DIR,;t t s,@inhibit_libc@,$inhibit_libc,;t t +s,@BUILD_PREFIX@,$BUILD_PREFIX,;t t +s,@BUILD_PREFIX_1@,$BUILD_PREFIX_1,;t t s,@CC_FOR_BUILD@,$CC_FOR_BUILD,;t t s,@BUILD_CFLAGS@,$BUILD_CFLAGS,;t t s,@STMP_FIXINC@,$STMP_FIXINC,;t t s,@STMP_FIXPROTO@,$STMP_FIXPROTO,;t t -s,@collect2@,$collect2,;t t -s,@gcc_cv_as@,$gcc_cv_as,;t t -s,@ORIGINAL_AS_FOR_TARGET@,$ORIGINAL_AS_FOR_TARGET,;t t -s,@gcc_cv_ld@,$gcc_cv_ld,;t t -s,@ORIGINAL_LD_FOR_TARGET@,$ORIGINAL_LD_FOR_TARGET,;t t -s,@gcc_cv_nm@,$gcc_cv_nm,;t t -s,@ORIGINAL_NM_FOR_TARGET@,$ORIGINAL_NM_FOR_TARGET,;t t -s,@gcc_cv_objdump@,$gcc_cv_objdump,;t t s,@libgcc_visibility@,$libgcc_visibility,;t t +s,@gthread_flags@,$gthread_flags,;t t s,@GGC@,$GGC,;t t s,@zlibdir@,$zlibdir,;t t s,@zlibinc@,$zlibinc,;t t @@ -17265,7 +13204,6 @@ s,@all_gtfiles_files_files@,$all_gtfiles_files_files,;t t s,@all_lang_makefrags@,$all_lang_makefrags,;t t s,@all_lang_makefiles@,$all_lang_makefiles,;t t s,@all_languages@,$all_languages,;t t -s,@all_selected_languages@,$all_selected_languages,;t t s,@all_stagestuff@,$all_stagestuff,;t t s,@build_exeext@,$build_exeext,;t t s,@build_install_headers_dir@,$build_install_headers_dir,;t t @@ -17287,6 +13225,10 @@ s,@extra_programs@,$extra_programs,;t t s,@float_h_file@,$float_h_file,;t t s,@gcc_config_arguments@,$gcc_config_arguments,;t t s,@gcc_gxx_include_dir@,$gcc_gxx_include_dir,;t t +s,@libstdcxx_incdir@,$libstdcxx_incdir,;t t +s,@gcc_version@,$gcc_version,;t t +s,@gcc_version_full@,$gcc_version_full,;t t +s,@gcc_version_trigger@,$gcc_version_trigger,;t t s,@host_exeext@,$host_exeext,;t t s,@host_xm_file_list@,$host_xm_file_list,;t t s,@host_xm_include_list@,$host_xm_include_list,;t t @@ -17303,6 +13245,7 @@ s,@out_file@,$out_file,;t t s,@out_object_file@,$out_object_file,;t t s,@stage_prefix_set_by_configure@,$stage_prefix_set_by_configure,;t t s,@quoted_stage_prefix_set_by_configure@,$quoted_stage_prefix_set_by_configure,;t t +s,@symbolic_link@,$symbolic_link,;t t s,@thread_file@,$thread_file,;t t s,@tm_file_list@,$tm_file_list,;t t s,@tm_include_list@,$tm_include_list,;t t @@ -17312,11 +13255,11 @@ s,@tm_p_include_list@,$tm_p_include_list,;t t s,@xm_file_list@,$xm_file_list,;t t s,@xm_include_list@,$xm_include_list,;t t s,@xm_defines@,$xm_defines,;t t +s,@target_noncanonical@,$target_noncanonical,;t t s,@c_target_objs@,$c_target_objs,;t t s,@cxx_target_objs@,$cxx_target_objs,;t t s,@target_cpu_default@,$target_cpu_default,;t t -s,@GMPLIBS@,$GMPLIBS,;t t -s,@GMPINC@,$GMPINC,;t t +s,@set_gcc_lib_path@,$set_gcc_lib_path,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t /@language_hooks@/r $language_hooks @@ -17897,7 +13840,7 @@ case ${CONFIG_HEADERS} in echo > cstamp-h ;; esac # Make sure all the subdirs exist. -for d in $subdirs doc build +for d in $subdirs do test -d $d || mkdir $d done @@ -17907,20 +13850,18 @@ done # FLAGS_TO_PASS has been modified to solve the problem there. # This is virtually a duplicate of what happens in configure.lang; we do # an extra check to make sure this only happens if ln -s can be used. -case "$LN_S" in - *-s*) - for d in ${subdirs} ; do +if test "$symbolic_link" = "ln -s"; then + for d in ${subdirs} fixinc ; do STARTDIR=`${PWDCMD-pwd}` cd $d for t in stage1 stage2 stage3 stage4 stageprofile stagefeedback include do rm -f $t - $LN_S ../$t $t 2>/dev/null + $symbolic_link ../$t $t 2>/dev/null done cd $STARTDIR - done - ;; -esac + done +else true ; fi ;; esac done diff --git a/contrib/gcc/cp/decl.c b/contrib/gcc/cp/decl.c index c3d71bc..451993e 100644 --- a/contrib/gcc/cp/decl.c +++ b/contrib/gcc/cp/decl.c @@ -1,6 +1,6 @@ /* Process declarations and variables for C++ compiler. Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -17,8 +17,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* Process declarations and symbol lookup for C++ front end. @@ -39,6 +39,7 @@ Boston, MA 02110-1301, USA. */ #include "cp-tree.h" #include "tree-inline.h" #include "decl.h" +#include "lex.h" #include "output.h" #include "except.h" #include "toplev.h" @@ -50,9 +51,8 @@ Boston, MA 02110-1301, USA. */ #include "diagnostic.h" #include "debug.h" #include "timevar.h" -#include "tree-flow.h" -static tree grokparms (cp_parameter_declarator *, tree *); +static tree grokparms (tree, tree *); static const char *redeclaration_error_message (tree, tree); static int decl_jump_unsafe (tree); @@ -61,12 +61,13 @@ static int ambi_op_p (enum tree_code); static int unary_op_p (enum tree_code); static void push_local_name (tree); static tree grok_reference_init (tree, tree, tree, tree *); -static tree grokvardecl (tree, tree, const cp_decl_specifier_seq *, - int, int, tree); +static tree grokfndecl (tree, tree, tree, tree, tree, int, + enum overload_flags, tree, + tree, int, int, int, int, int, int, tree); +static tree grokvardecl (tree, tree, RID_BIT_TYPE *, int, int, tree); static void record_unknown_type (tree, const char *); -static tree builtin_function_1 (const char *, tree, tree, - enum built_in_function code, - enum built_in_class cl, const char *, +static tree builtin_function_1 (const char *, tree, tree, int, + enum built_in_class, const char *, tree); static tree build_library_fn_1 (tree, enum tree_code, tree); static int member_function_or_else (tree, tree, enum overload_flags); @@ -77,9 +78,19 @@ static hashval_t typename_hash (const void *); static int typename_compare (const void *, const void *); static tree local_variable_p_walkfn (tree *, int *, void *); static tree record_builtin_java_type (const char *, int); -static const char *tag_name (enum tag_types); -static tree lookup_and_check_tag (enum tag_types, tree, tag_scope, bool); +static const char *tag_name (enum tag_types code); static int walk_namespaces_r (tree, walk_namespaces_fn, void *); +static int walk_globals_r (tree, void*); +static int walk_vtables_r (tree, void*); +static tree make_label_decl (tree, int); +static void use_label (tree); +static void check_previous_goto_1 (tree, struct cp_binding_level *, tree, + const location_t *); +static void check_previous_goto (struct named_label_use_list *); +static void check_switch_goto (struct cp_binding_level *); +static void check_previous_gotos (tree); +static void pop_label (tree, tree); +static void pop_labels (tree); static void maybe_deduce_size_from_array_init (tree, tree); static void layout_var_decl (tree); static void maybe_commonize_var (tree); @@ -87,6 +98,7 @@ static tree check_initializer (tree, tree, int, tree *); static void make_rtl_for_nonlocal_decl (tree, tree, const char *); static void save_function_data (tree); static void check_function_type (tree, tree); +static void begin_constructor_body (void); static void finish_constructor_body (void); static void begin_destructor_body (void); static void finish_destructor_body (void); @@ -97,14 +109,21 @@ static tree start_cleanup_fn (void); static void end_cleanup_fn (void); static tree cp_make_fname_decl (tree, int); static void initialize_predefined_identifiers (void); -static tree check_special_function_return_type +static tree check_special_function_return_type (special_function_kind, tree, tree); static tree push_cp_library_fn (enum tree_code, tree); static tree build_cp_library_fn (tree, enum tree_code, tree); static void store_parm_decls (tree); +static int cp_missing_noreturn_ok_p (tree); static void initialize_local_var (tree, tree); static void expand_static_init (tree, tree); static tree next_initializable_field (tree); +static tree reshape_init (tree, tree *); +static bool reshape_init_array (tree, tree, tree *, tree); +static tree build_typename_type (tree, tree, tree); + +/* Erroneous argument lists can use this *IFF* they do not modify it. */ +tree error_mark_list; /* The following symbols are subsumed in the cp_global_trees array, and listed here individually for documentation purposes. @@ -115,6 +134,12 @@ static tree next_initializable_field (tree); tree vtable_entry_type; tree delta_type_node; tree __t_desc_type_node; + tree ti_desc_type_node; + tree bltn_desc_type_node, ptr_desc_type_node; + tree ary_desc_type_node, func_desc_type_node, enum_desc_type_node; + tree class_desc_type_node, si_class_desc_type_node, vmi_class_desc_type_node; + tree ptm_desc_type_node; + tree base_desc_type_node; tree class_type_node; tree unknown_type_node; @@ -141,7 +166,9 @@ static tree next_initializable_field (tree); Used by RTTI tree type_info_type_node, tinfo_decl_id, tinfo_decl_type; - tree tinfo_var_id; */ + tree tinfo_var_id; + +*/ tree cp_global_trees[CPTI_MAX]; @@ -153,6 +180,20 @@ tree global_type_node; /* The node that holds the "name" of the global scope. */ tree global_scope_name; +/* Used only for jumps to as-yet undefined labels, since jumps to + defined labels can have their validity checked immediately. */ + +struct named_label_use_list GTY(()) +{ + struct cp_binding_level *binding_level; + tree names_in_scope; + tree label_decl; + location_t o_goto_locus; + struct named_label_use_list *next; +}; + +#define named_label_uses cp_function_chain->x_named_label_uses + #define local_names cp_function_chain->x_local_names /* A list of objects which have constructors or destructors @@ -167,58 +208,20 @@ tree static_aggregates; tree integer_two_node, integer_three_node; -/* Used only for jumps to as-yet undefined labels, since jumps to - defined labels can have their validity checked immediately. */ - -struct named_label_use_entry GTY(()) -{ - struct named_label_use_entry *next; - /* The binding level to which this entry is *currently* attached. - This is initially the binding level in which the goto appeared, - but is modified as scopes are closed. */ - struct cp_binding_level *binding_level; - /* The head of the names list that was current when the goto appeared, - or the inner scope popped. These are the decls that will *not* be - skipped when jumping to the label. */ - tree names_in_scope; - /* The location of the goto, for error reporting. */ - location_t o_goto_locus; - /* True if an OpenMP structured block scope has been closed since - the goto appeared. This means that the branch from the label will - illegally exit an OpenMP scope. */ - bool in_omp_scope; -}; - /* A list of all LABEL_DECLs in the function that have names. Here so we can clear out their names' definitions at the end of the function, and so we can check the validity of jumps to these labels. */ -struct named_label_entry GTY(()) +struct named_label_list GTY(()) { - /* The decl itself. */ - tree label_decl; - - /* The binding level to which the label is *currently* attached. - This is initially set to the binding level in which the label - is defined, but is modified as scopes are closed. */ struct cp_binding_level *binding_level; - /* The head of the names list that was current when the label was - defined, or the inner scope popped. These are the decls that will - be skipped when jumping to the label. */ tree names_in_scope; - /* A tree list of all decls from all binding levels that would be - crossed by a backward branch to the label. */ + tree old_value; + tree label_decl; tree bad_decls; - - /* A list of uses of the label, before the label is defined. */ - struct named_label_use_entry *uses; - - /* The following bits are set after the label is defined, and are - updated as scopes are popped. They indicate that a backward jump - to the label will illegally enter a scope of the given flavor. */ - bool in_try_scope; - bool in_catch_scope; - bool in_omp_scope; + struct named_label_list *next; + unsigned int in_try_scope : 1; + unsigned int in_catch_scope : 1; }; #define named_labels cp_function_chain->x_named_labels @@ -232,7 +235,7 @@ int function_depth; with __attribute__((deprecated)). An object declared as __attribute__((deprecated)) suppresses warnings of uses of other deprecated items. */ - + enum deprecated_states { DEPRECATED_NORMAL, DEPRECATED_SUPPRESS @@ -240,6 +243,15 @@ enum deprecated_states { static enum deprecated_states deprecated_state = DEPRECATED_NORMAL; +/* Set by add_implicitly_declared_members() to keep those members from + being flagged as deprecated or reported as using deprecated + types. */ +int adding_implicit_members = 0; + +/* True if a declaration with an `extern' linkage specifier is being + processed. */ +bool have_extern_spec; + /* A TREE_LIST of VAR_DECLs. The TREE_PURPOSE is a RECORD_TYPE or UNION_TYPE; the TREE_VALUE is a VAR_DECL with that type. At the @@ -260,8 +272,8 @@ current_tmpl_spec_kind (int n_class_scopes) struct cp_binding_level *b; /* Scan through the template parameter scopes. */ - for (b = current_binding_level; - b->kind == sk_template_parms; + for (b = current_binding_level; + b->kind == sk_template_parms; b = b->level_chain) { /* If we see a specialization scope inside a parameter scope, @@ -305,7 +317,7 @@ current_tmpl_spec_kind (int n_class_scopes) /* We've not seen enough template headers to match all the specialized classes present. For example: - template <class T> void R<T>::S<T>::f(int); + template <class T> void R<T>::S<T>::f(int); This is invalid; there needs to be one set of template parameters for each class. */ @@ -314,7 +326,7 @@ current_tmpl_spec_kind (int n_class_scopes) /* We're processing a non-template declaration (even though it may be a member of a template class.) For example: - template <class T> void S<T>::f(int); + template <class T> void S<T>::f(int); The `class T' maches the `S<T>', leaving no template headers corresponding to the `f'. */ @@ -322,14 +334,14 @@ current_tmpl_spec_kind (int n_class_scopes) else if (n_template_parm_scopes > n_class_scopes + 1) /* We've got too many template headers. For example: - template <> template <class T> void f (T); + template <> template <class T> void f (T); There need to be more enclosing classes. */ return tsk_excessive_parms; else /* This must be a template. It's of the form: - template <class T> template <class U> void S<T>::f(U); + template <class T> template <class U> void S<T>::f(U); This is a specialization if the innermost level was a specialization; otherwise it's just a definition of the @@ -357,18 +369,14 @@ pop_label (tree label, tree old_value) { location_t location; - error ("label %q+D used but not defined", label); -#ifdef USE_MAPPED_LOCATION - location = input_location; /* FIXME want (input_filename, (line)0) */ -#else - location.file = input_filename; + cp_error_at ("label `%D' used but not defined", label); + location.file = input_filename; location.line = 0; -#endif /* Avoid crashing later. */ define_label (location, DECL_NAME (label)); } - else if (!TREE_USED (label)) - warning (OPT_Wunused_label, "label %q+D defined but not used", label); + else if (warn_unused_label && !TREE_USED (label)) + cp_warning_at ("label `%D' defined but not used", label); } SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), old_value); @@ -378,133 +386,23 @@ pop_label (tree label, tree old_value) go out of scope. BLOCK is the top-level block for the function. */ -static int -pop_labels_1 (void **slot, void *data) -{ - struct named_label_entry *ent = (struct named_label_entry *) *slot; - tree block = (tree) data; - - pop_label (ent->label_decl, NULL_TREE); - - /* Put the labels into the "variables" of the top-level block, - so debugger can see them. */ - TREE_CHAIN (ent->label_decl) = BLOCK_VARS (block); - BLOCK_VARS (block) = ent->label_decl; - - htab_clear_slot (named_labels, slot); - - return 1; -} - static void pop_labels (tree block) { - if (named_labels) - { - htab_traverse (named_labels, pop_labels_1, block); - named_labels = NULL; - } -} - -/* At the end of a block with local labels, restore the outer definition. */ - -static void -pop_local_label (tree label, tree old_value) -{ - struct named_label_entry dummy; - void **slot; - - pop_label (label, old_value); + struct named_label_list *link; - dummy.label_decl = label; - slot = htab_find_slot (named_labels, &dummy, NO_INSERT); - htab_clear_slot (named_labels, slot); -} - -/* The following two routines are used to interface to Objective-C++. - The binding level is purposely treated as an opaque type. */ - -void * -objc_get_current_scope (void) -{ - return current_binding_level; -} - -/* The following routine is used by the NeXT-style SJLJ exceptions; - variables get marked 'volatile' so as to not be clobbered by - _setjmp()/_longjmp() calls. All variables in the current scope, - as well as parent scopes up to (but not including) ENCLOSING_BLK - shall be thusly marked. */ - -void -objc_mark_locals_volatile (void *enclosing_blk) -{ - struct cp_binding_level *scope; - - for (scope = current_binding_level; - scope && scope != enclosing_blk; - scope = scope->level_chain) + /* Clear out the definitions of all label names, since their scopes + end here. */ + for (link = named_labels; link; link = link->next) { - tree decl; - - for (decl = scope->names; decl; decl = TREE_CHAIN (decl)) - objc_volatilize_decl (decl); - - /* Do not climb up past the current function. */ - if (scope->kind == sk_function_parms) - break; - } -} - -/* Update data for defined and undefined labels when leaving a scope. */ - -static int -poplevel_named_label_1 (void **slot, void *data) -{ - struct named_label_entry *ent = (struct named_label_entry *) *slot; - struct cp_binding_level *bl = (struct cp_binding_level *) data; - struct cp_binding_level *obl = bl->level_chain; - - if (ent->binding_level == bl) - { - tree decl; - - for (decl = ent->names_in_scope; decl; decl = TREE_CHAIN (decl)) - if (decl_jump_unsafe (decl)) - ent->bad_decls = tree_cons (NULL, decl, ent->bad_decls); - - ent->binding_level = obl; - ent->names_in_scope = obl->names; - switch (bl->kind) - { - case sk_try: - ent->in_try_scope = true; - break; - case sk_catch: - ent->in_catch_scope = true; - break; - case sk_omp: - ent->in_omp_scope = true; - break; - default: - break; - } + pop_label (link->label_decl, link->old_value); + /* Put the labels into the "variables" of the top-level block, + so debugger can see them. */ + TREE_CHAIN (link->label_decl) = BLOCK_VARS (block); + BLOCK_VARS (block) = link->label_decl; } - else if (ent->uses) - { - struct named_label_use_entry *use; - for (use = ent->uses; use ; use = use->next) - if (use->binding_level == bl) - { - use->binding_level = obl; - use->names_in_scope = obl->names; - if (bl->kind == sk_omp) - use->in_omp_scope = true; - } - } - - return 1; + named_labels = NULL; } /* Exit a binding level. @@ -532,38 +430,65 @@ poplevel (int keep, int reverse, int functionbody) int tmp = functionbody; int real_functionbody; tree subblocks; - tree block; + tree block = NULL_TREE; tree decl; int leaving_for_scope; scope_kind kind; timevar_push (TV_NAME_LOOKUP); - restart: - block = NULL_TREE; - - gcc_assert (current_binding_level->kind != sk_class); + my_friendly_assert (current_binding_level->kind != sk_class, 19990916); real_functionbody = (current_binding_level->kind == sk_cleanup ? ((functionbody = 0), tmp) : functionbody); subblocks = functionbody >= 0 ? current_binding_level->blocks : 0; - gcc_assert (!VEC_length(cp_class_binding, - current_binding_level->class_shadowed)); + my_friendly_assert (!current_binding_level->class_shadowed, + 19990414); /* We used to use KEEP == 2 to indicate that the new block should go at the beginning of the list of blocks at this binding level, rather than the end. This hack is no longer used. */ - gcc_assert (keep == 0 || keep == 1); + my_friendly_assert (keep == 0 || keep == 1, 0); if (current_binding_level->keep) keep = 1; /* Any uses of undefined labels, and any defined labels, now operate under constraints of next binding contour. */ - if (cfun && !functionbody && named_labels) - htab_traverse (named_labels, poplevel_named_label_1, - current_binding_level); + if (cfun && !functionbody) + { + struct cp_binding_level *level_chain; + level_chain = current_binding_level->level_chain; + if (level_chain) + { + struct named_label_use_list *uses; + struct named_label_list *labels; + for (labels = named_labels; labels; labels = labels->next) + if (labels->binding_level == current_binding_level) + { + tree decl; + if (current_binding_level->kind == sk_try) + labels->in_try_scope = 1; + if (current_binding_level->kind == sk_catch) + labels->in_catch_scope = 1; + for (decl = labels->names_in_scope; decl; + decl = TREE_CHAIN (decl)) + if (decl_jump_unsafe (decl)) + labels->bad_decls = tree_cons (NULL_TREE, decl, + labels->bad_decls); + labels->binding_level = level_chain; + labels->names_in_scope = level_chain->names; + } + + for (uses = named_label_uses; uses; uses = uses->next) + if (uses->binding_level == current_binding_level) + { + uses->binding_level = level_chain; + uses->names_in_scope = level_chain->names; + } + } + } /* Get the decls in the order they were written. Usually current_binding_level->names is in reverse order. @@ -575,6 +500,36 @@ poplevel (int keep, int reverse, int functionbody) else decls = current_binding_level->names; + /* Output any nested inline functions within this block + if they weren't already output. */ + for (decl = decls; decl; decl = TREE_CHAIN (decl)) + if (TREE_CODE (decl) == FUNCTION_DECL + && ! TREE_ASM_WRITTEN (decl) + && DECL_INITIAL (decl) != NULL_TREE + && TREE_ADDRESSABLE (decl) + && decl_function_context (decl) == current_function_decl) + { + /* If this decl was copied from a file-scope decl + on account of a block-scope extern decl, + propagate TREE_ADDRESSABLE to the file-scope decl. */ + if (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE) + TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; + else + { + push_function_context (); + output_inline_function (decl); + pop_function_context (); + } + } + + /* When not in function-at-a-time mode, expand_end_bindings will + warn about unused variables. But, in function-at-a-time mode + expand_end_bindings is not passed the list of variables in the + current scope, and therefore no warning is emitted. So, we + explicitly warn here. */ + if (!processing_template_decl) + warn_about_unused_variables (getdecls ()); + /* If there were any declarations or structure tags in that level, or if this level is a function body, create a BLOCK to record them for the life of this function. */ @@ -599,44 +554,33 @@ poplevel (int keep, int reverse, int functionbody) leaving_for_scope = current_binding_level->kind == sk_for && flag_new_for_scope == 1; - /* Before we remove the declarations first check for unused variables. */ - if (warn_unused_variable - && !processing_template_decl) - for (decl = getdecls (); decl; decl = TREE_CHAIN (decl)) - if (TREE_CODE (decl) == VAR_DECL - && ! TREE_USED (decl) - && ! DECL_IN_SYSTEM_HEADER (decl) - && DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl)) - warning (OPT_Wunused_variable, "unused variable %q+D", decl); - /* Remove declarations for all the DECLs in this level. */ for (link = decls; link; link = TREE_CHAIN (link)) { if (leaving_for_scope && TREE_CODE (link) == VAR_DECL - && DECL_NAME (link)) + && DECL_NAME (link)) { - tree name = DECL_NAME (link); - cxx_binding *ob; + cxx_binding *outer_binding + = IDENTIFIER_BINDING (DECL_NAME (link))->previous; tree ns_binding; - ob = outer_binding (name, - IDENTIFIER_BINDING (name), - /*class_p=*/true); - if (!ob) - ns_binding = IDENTIFIER_NAMESPACE_VALUE (name); + if (!outer_binding) + ns_binding = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (link)); else ns_binding = NULL_TREE; - if (ob && ob->scope == current_binding_level->level_chain) + if (outer_binding + && outer_binding->scope == current_binding_level->level_chain) /* We have something like: - int i; - for (int i; ;); + int i; + for (int i; ;); and we are leaving the `for' scope. There's no reason to keep the binding of the inner `i' in this case. */ - pop_binding (name, link); - else if ((ob && (TREE_CODE (ob->value) == TYPE_DECL)) + pop_binding (DECL_NAME (link), link); + else if ((outer_binding + && (TREE_CODE (outer_binding->value) == TYPE_DECL)) || (ns_binding && TREE_CODE (ns_binding) == TYPE_DECL)) /* Here, we have something like: @@ -648,7 +592,7 @@ poplevel (int keep, int reverse, int functionbody) We must pop the for-scope binding so we know what's a type and what isn't. */ - pop_binding (name, link); + pop_binding (DECL_NAME (link), link); else { /* Mark this VAR_DECL as dead so that we can tell we left it @@ -657,11 +601,8 @@ poplevel (int keep, int reverse, int functionbody) /* Keep track of what should have happened when we popped the binding. */ - if (ob && ob->value) - { - SET_DECL_SHADOWED_FOR_VAR (link, ob->value); - DECL_HAS_SHADOWED_FOR_VAR_P (link) = 1; - } + if (outer_binding && outer_binding->value) + DECL_SHADOWED_FOR_VAR (link) = outer_binding->value; /* Add it to the list of dead variables in the next outermost binding to that we can remove these when we @@ -673,26 +614,21 @@ poplevel (int keep, int reverse, int functionbody) /* Although we don't pop the cxx_binding, we do clear its SCOPE since the scope is going away now. */ - IDENTIFIER_BINDING (name)->scope - = current_binding_level->level_chain; + IDENTIFIER_BINDING (DECL_NAME (link))->scope = NULL; } } else { - tree name; - /* Remove the binding. */ decl = link; - if (TREE_CODE (decl) == TREE_LIST) decl = TREE_VALUE (decl); - name = decl; - - if (TREE_CODE (name) == OVERLOAD) - name = OVL_FUNCTION (name); - - gcc_assert (DECL_P (name)); - pop_binding (DECL_NAME (name), decl); + if (DECL_P (decl)) + pop_binding (DECL_NAME (decl), decl); + else if (TREE_CODE (decl) == OVERLOAD) + pop_binding (DECL_NAME (OVL_FUNCTION (decl)), decl); + else + abort (); } } @@ -711,7 +647,7 @@ poplevel (int keep, int reverse, int functionbody) for (link = current_binding_level->shadowed_labels; link; link = TREE_CHAIN (link)) - pop_local_label (TREE_VALUE (link), TREE_PURPOSE (link)); + pop_label (TREE_VALUE (link), TREE_PURPOSE (link)); /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs list if a `using' declaration put them there. The debugging @@ -744,17 +680,6 @@ poplevel (int keep, int reverse, int functionbody) } kind = current_binding_level->kind; - if (kind == sk_cleanup) - { - tree stmt; - - /* If this is a temporary binding created for a cleanup, then we'll - have pushed a statement list level. Pop that, create a new - BIND_EXPR for the block, and insert it into the stream. */ - stmt = pop_stmt_list (current_binding_level->statement_list); - stmt = c_build_bind_expr (block, stmt); - add_stmt (stmt); - } leave_scope (); if (functionbody) @@ -778,13 +703,48 @@ poplevel (int keep, int reverse, int functionbody) if (block) TREE_USED (block) = 1; - /* All temporary bindings created for cleanups are popped silently. */ + /* Take care of compiler's internal binding structures. */ if (kind == sk_cleanup) - goto restart; + { + tree scope_stmts; + + scope_stmts + = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/1); + if (block) + { + SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block; + SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block; + } + + block = poplevel (keep, reverse, functionbody); + } POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, block); } +/* Delete the node BLOCK from the current binding level. + This is used for the block inside a stmt expr ({...}) + so that the block can be reinserted where appropriate. */ + +void +delete_block (tree block) +{ + tree t; + if (current_binding_level->blocks == block) + current_binding_level->blocks = TREE_CHAIN (block); + for (t = current_binding_level->blocks; t;) + { + if (TREE_CHAIN (t) == block) + TREE_CHAIN (t) = TREE_CHAIN (block); + else + t = TREE_CHAIN (t); + } + TREE_CHAIN (block) = NULL_TREE; + /* Clear TREE_USED which is always set by poplevel. + The flag is set again if insert_block is called. */ + TREE_USED (block) = 0; +} + /* Insert BLOCK at the end of the list of subblocks of the current binding level. This is used when a BIND_EXPR is expanded, to handle the BLOCK node inside the BIND_EXPR. */ @@ -797,6 +757,74 @@ insert_block (tree block) = chainon (current_binding_level->blocks, block); } +/* Set the BLOCK node for the innermost scope + (the one we are currently in). */ + +void +set_block (tree block ATTRIBUTE_UNUSED ) +{ + /* The RTL expansion machinery requires us to provide this callback, + but it is not applicable in function-at-a-time mode. */ +} + +/* Returns nonzero if T is a virtual function table. */ + +int +vtable_decl_p (tree t, void* data ATTRIBUTE_UNUSED ) +{ + return (TREE_CODE (t) == VAR_DECL && DECL_VIRTUAL_P (t)); +} + +/* Returns nonzero if T is a TYPE_DECL for a type with virtual + functions. */ + +int +vtype_decl_p (tree t, void *data ATTRIBUTE_UNUSED ) +{ + return (TREE_CODE (t) == TYPE_DECL + && TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE + && TYPE_POLYMORPHIC_P (TREE_TYPE (t))); +} + +struct walk_globals_data { + walk_globals_pred p; + walk_globals_fn f; + void *data; +}; + +/* Walk the vtable declarations in NAMESPACE. Whenever one is found + for which P returns nonzero, call F with its address. If any call + to F returns a nonzero value, return a nonzero value. */ + +static int +walk_vtables_r (tree namespace, void* data) +{ + struct walk_globals_data* wgd = (struct walk_globals_data *) data; + walk_globals_fn f = wgd->f; + void *d = wgd->data; + tree decl = NAMESPACE_LEVEL (namespace)->vtables; + int result = 0; + + for (; decl ; decl = TREE_CHAIN (decl)) + result |= (*f) (&decl, d); + + return result; +} + +/* Walk the vtable declarations. Whenever one is found for which P + returns nonzero, call F with its address. If any call to F + returns a nonzero value, return a nonzero value. */ +bool +walk_vtables (walk_globals_pred p, walk_globals_fn f, void *data) +{ + struct walk_globals_data wgd; + wgd.p = p; + wgd.f = f; + wgd.data = data; + + return walk_namespaces (walk_vtables_r, &wgd); +} + /* Walk all the namespaces contained NAMESPACE, including NAMESPACE itself, calling F for each. The DATA is passed to F as well. */ @@ -804,7 +832,7 @@ static int walk_namespaces_r (tree namespace, walk_namespaces_fn f, void* data) { int result = 0; - tree current = NAMESPACE_LEVEL (namespace)->namespaces; + tree current = NAMESPACE_LEVEL (namespace)->namespaces; result |= (*f) (namespace, data); @@ -823,6 +851,53 @@ walk_namespaces (walk_namespaces_fn f, void* data) return walk_namespaces_r (global_namespace, f, data); } +/* Walk the global declarations in NAMESPACE. Whenever one is found + for which P returns nonzero, call F with its address. If any call + to F returns a nonzero value, return a nonzero value. */ + +static int +walk_globals_r (tree namespace, void* data) +{ + struct walk_globals_data* wgd = (struct walk_globals_data *) data; + walk_globals_pred p = wgd->p; + walk_globals_fn f = wgd->f; + void *d = wgd->data; + tree *t; + int result = 0; + + t = &NAMESPACE_LEVEL (namespace)->names; + + while (*t) + { + tree glbl = *t; + + if ((*p) (glbl, d)) + result |= (*f) (t, d); + + /* If F changed *T, then *T still points at the next item to + examine. */ + if (*t == glbl) + t = &TREE_CHAIN (*t); + } + + return result; +} + +/* Walk the global declarations. Whenever one is found for which P + returns true, call F with its address. If any call to F + returns true, return true. */ + +bool +walk_globals (walk_globals_pred p, walk_globals_fn f, void *data) +{ + struct walk_globals_data wgd; + wgd.p = p; + wgd.f = f; + wgd.data = data; + + return walk_namespaces (walk_globals_r, &wgd); +} + /* Call wrapup_globals_declarations for the globals in NAMESPACE. If DATA is non-NULL, this is the last time we will call wrapup_global_declarations for this NAMESPACE. */ @@ -831,15 +906,14 @@ int wrapup_globals_for_namespace (tree namespace, void* data) { struct cp_binding_level *level = NAMESPACE_LEVEL (namespace); - VEC(tree,gc) *statics = level->static_decls; - tree *vec = VEC_address (tree, statics); - int len = VEC_length (tree, statics); + varray_type statics = level->static_decls; + tree *vec = &VARRAY_TREE (statics, 0); + int len = VARRAY_ACTIVE_SIZE (statics); int last_time = (data != 0); if (last_time) { check_global_declarations (vec, len); - emit_debug_global_declarations (vec, len); return 0; } @@ -878,13 +952,15 @@ push_local_name (tree decl) tree t, name; timevar_push (TV_NAME_LOOKUP); + if (!local_names) + VARRAY_TREE_INIT (local_names, 8, "local_names"); name = DECL_NAME (decl); - nelts = VEC_length (tree, local_names); + nelts = VARRAY_ACTIVE_SIZE (local_names); for (i = 0; i < nelts; i++) { - t = VEC_index (tree, local_names, i); + t = VARRAY_TREE (local_names, i); if (DECL_NAME (t) == name) { if (!DECL_LANG_SPECIFIC (decl)) @@ -895,13 +971,13 @@ push_local_name (tree decl) else DECL_DISCRIMINATOR (decl) = 1; - VEC_replace (tree, local_names, i, decl); + VARRAY_TREE (local_names, i) = decl; timevar_pop (TV_NAME_LOOKUP); return; } } - VEC_safe_push (tree, gc, local_names, decl); + VARRAY_PUSH_TREE (local_names, decl); timevar_pop (TV_NAME_LOOKUP); } @@ -938,15 +1014,15 @@ decls_match (tree newdecl, tree olddecl) return 0; if (TREE_CODE (f1) != TREE_CODE (f2)) - return 0; + return 0; if (same_type_p (TREE_TYPE (f1), TREE_TYPE (f2))) { if (p2 == NULL_TREE && DECL_EXTERN_C_P (olddecl) && (DECL_BUILT_IN (olddecl) #ifndef NO_IMPLICIT_EXTERN_C - || (DECL_IN_SYSTEM_HEADER (newdecl) && !DECL_CLASS_SCOPE_P (newdecl)) - || (DECL_IN_SYSTEM_HEADER (olddecl) && !DECL_CLASS_SCOPE_P (olddecl)) + || (DECL_IN_SYSTEM_HEADER (newdecl) && !DECL_CLASS_SCOPE_P (newdecl)) + || (DECL_IN_SYSTEM_HEADER (olddecl) && !DECL_CLASS_SCOPE_P (olddecl)) #endif )) { @@ -957,11 +1033,11 @@ decls_match (tree newdecl, tree olddecl) #ifndef NO_IMPLICIT_EXTERN_C else if (p1 == NULL_TREE && (DECL_EXTERN_C_P (olddecl) - && DECL_IN_SYSTEM_HEADER (olddecl) - && !DECL_CLASS_SCOPE_P (olddecl)) + && DECL_IN_SYSTEM_HEADER (olddecl) + && !DECL_CLASS_SCOPE_P (olddecl)) && (DECL_EXTERN_C_P (newdecl) - && DECL_IN_SYSTEM_HEADER (newdecl) - && !DECL_CLASS_SCOPE_P (newdecl))) + && DECL_IN_SYSTEM_HEADER (newdecl) + && !DECL_CLASS_SCOPE_P (newdecl))) { types_match = self_promoting_args_p (p2); TREE_TYPE (newdecl) = TREE_TYPE (olddecl); @@ -995,13 +1071,7 @@ decls_match (tree newdecl, tree olddecl) /* Need to check scope for variable declaration (VAR_DECL). For typedef (TYPE_DECL), scope is ignored. */ if (TREE_CODE (newdecl) == VAR_DECL - && CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl) - /* [dcl.link] - Two declarations for an object with C language linkage - with the same name (ignoring the namespace that qualify - it) that appear in different namespace scopes refer to - the same object. */ - && !(DECL_EXTERN_C_P (olddecl) && DECL_EXTERN_C_P (newdecl))) + && CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl)) return 0; if (TREE_TYPE (newdecl) == error_mark_node) @@ -1031,6 +1101,11 @@ decls_match (tree newdecl, tree olddecl) void warn_extern_redeclared_static (tree newdecl, tree olddecl) { + static const char *const explicit_extern_static_warning + = "`%D' was declared `extern' and later `static'"; + static const char *const implicit_extern_static_warning + = "`%D' was declared implicitly `extern' and later `static'"; + tree name; if (TREE_CODE (newdecl) == TYPE_DECL @@ -1056,43 +1131,10 @@ warn_extern_redeclared_static (tree newdecl, tree olddecl) return; name = DECL_ASSEMBLER_NAME (newdecl); - pedwarn ("%qD was declared %<extern%> and later %<static%>", newdecl); - pedwarn ("previous declaration of %q+D", olddecl); -} - -/* NEW_DECL is a redeclaration of OLD_DECL; both are functions or - function templates. If their exception specifications do not - match, issue an a diagnostic. */ - -static void -check_redeclaration_exception_specification (tree new_decl, - tree old_decl) -{ - tree new_type; - tree old_type; - tree new_exceptions; - tree old_exceptions; - - new_type = TREE_TYPE (new_decl); - new_exceptions = TYPE_RAISES_EXCEPTIONS (new_type); - old_type = TREE_TYPE (old_decl); - old_exceptions = TYPE_RAISES_EXCEPTIONS (old_type); - - /* [except.spec] - - If any declaration of a function has an exception-specification, - all declarations, including the definition and an explicit - specialization, of that function shall have an - exception-specification with the same set of type-ids. */ - if ((pedantic || ! DECL_IN_SYSTEM_HEADER (old_decl)) - && ! DECL_IS_BUILTIN (old_decl) - && flag_exceptions - && !comp_except_specs (new_exceptions, old_exceptions, - /*exact=*/true)) - { - error ("declaration of %qF throws different exceptions", new_decl); - error ("from previous declaration %q+F", old_decl); - } + pedwarn (IDENTIFIER_IMPLICIT_DECL (name) + ? implicit_extern_static_warning + : explicit_extern_static_warning, newdecl); + cp_pedwarn_at ("previous declaration of `%D'", olddecl); } /* If NEWDECL is a redeclaration of OLDDECL, merge the declarations. @@ -1100,17 +1142,14 @@ check_redeclaration_exception_specification (tree new_decl, error_mark_node is returned. Otherwise, OLDDECL is returned. If NEWDECL is not a redeclaration of OLDDECL, NULL_TREE is - returned. - - NEWDECL_IS_FRIEND is true if NEWDECL was declared as a friend. */ + returned. */ tree -duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) +duplicate_decls (tree newdecl, tree olddecl) { unsigned olddecl_uid = DECL_UID (olddecl); - int olddecl_friend = 0, types_match = 0, hidden_friend = 0; + int olddecl_friend = 0, types_match = 0; int new_defines_function = 0; - tree new_template; if (newdecl == olddecl) return olddecl; @@ -1124,7 +1163,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) about the same declaration, so just pretend the types match here. */ if (TREE_TYPE (newdecl) == error_mark_node || TREE_TYPE (olddecl) == error_mark_node) - return error_mark_node; + types_match = 1; if (DECL_P (olddecl) && TREE_CODE (newdecl) == FUNCTION_DECL @@ -1143,19 +1182,18 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) && DECL_UNINLINABLE (olddecl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) { - warning (OPT_Wattributes, "function %q+D redeclared as inline", - newdecl); - warning (OPT_Wattributes, "previous declaration of %q+D " - "with attribute noinline", olddecl); + warning ("%Jfunction '%D' redeclared as inline", newdecl, newdecl); + warning ("%Jprevious declaration of '%D' with attribute noinline", + olddecl, olddecl); } else if (DECL_DECLARED_INLINE_P (olddecl) && DECL_UNINLINABLE (newdecl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) { - warning (OPT_Wattributes, "function %q+D redeclared with " - "attribute noinline", newdecl); - warning (OPT_Wattributes, "previous declaration of %q+D was inline", - olddecl); + warning ("%Jfunction '%D' redeclared with attribute noinline", + newdecl, newdecl); + warning ("%Jprevious declaration of '%D' was inline", + olddecl, olddecl); } } @@ -1163,78 +1201,42 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (TREE_CODE (olddecl) == FUNCTION_DECL && DECL_ARTIFICIAL (olddecl)) { - gcc_assert (!DECL_HIDDEN_FRIEND_P (olddecl)); if (TREE_CODE (newdecl) != FUNCTION_DECL) { - /* Avoid warnings redeclaring built-ins which have not been - explicitly declared. */ - if (DECL_ANTICIPATED (olddecl)) - return NULL_TREE; + /* Avoid warnings redeclaring anticipated built-ins. */ + if (DECL_ANTICIPATED (olddecl)) + return NULL_TREE; /* If you declare a built-in or predefined function name as static, the old definition is overridden, but optionally warn this was a bad choice of name. */ if (! TREE_PUBLIC (newdecl)) { - warning (OPT_Wshadow, "shadowing %s function %q#D", - DECL_BUILT_IN (olddecl) ? "built-in" : "library", - olddecl); + if (warn_shadow) + warning ("shadowing %s function `%#D'", + DECL_BUILT_IN (olddecl) ? "built-in" : "library", + olddecl); /* Discard the old built-in function. */ return NULL_TREE; } /* If the built-in is not ansi, then programs can override it even globally without an error. */ else if (! DECL_BUILT_IN (olddecl)) - warning (0, "library function %q#D redeclared as non-function %q#D", - olddecl, newdecl); + warning ("library function `%#D' redeclared as non-function `%#D'", + olddecl, newdecl); else { - error ("declaration of %q#D", newdecl); - error ("conflicts with built-in declaration %q#D", - olddecl); + error ("declaration of `%#D'", newdecl); + error ("conflicts with built-in declaration `%#D'", + olddecl); } return NULL_TREE; } else if (!types_match) { - /* Avoid warnings redeclaring built-ins which have not been - explicitly declared. */ - if (DECL_ANTICIPATED (olddecl)) - { - /* Deal with fileptr_type_node. FILE type is not known - at the time we create the builtins. */ - tree t1, t2; - - for (t1 = TYPE_ARG_TYPES (TREE_TYPE (newdecl)), - t2 = TYPE_ARG_TYPES (TREE_TYPE (olddecl)); - t1 || t2; - t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) - if (!t1 || !t2) - break; - else if (TREE_VALUE (t2) == fileptr_type_node) - { - tree t = TREE_VALUE (t1); - - if (TREE_CODE (t) == POINTER_TYPE - && TYPE_NAME (TREE_TYPE (t)) - && DECL_NAME (TYPE_NAME (TREE_TYPE (t))) - == get_identifier ("FILE") - && compparms (TREE_CHAIN (t1), TREE_CHAIN (t2))) - { - tree oldargs = TYPE_ARG_TYPES (TREE_TYPE (olddecl)); - - TYPE_ARG_TYPES (TREE_TYPE (olddecl)) - = TYPE_ARG_TYPES (TREE_TYPE (newdecl)); - types_match = decls_match (newdecl, olddecl); - if (types_match) - return duplicate_decls (newdecl, olddecl, - newdecl_is_friend); - TYPE_ARG_TYPES (TREE_TYPE (olddecl)) = oldargs; - } - } - else if (! same_type_p (TREE_VALUE (t1), TREE_VALUE (t2))) - break; - } + /* Avoid warnings redeclaring anticipated built-ins. */ + if (DECL_ANTICIPATED (olddecl)) + ; /* Do nothing yet. */ else if ((DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl)) || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), @@ -1244,25 +1246,24 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (TREE_PUBLIC (newdecl)) { - warning (0, "new declaration %q#D", newdecl); - warning (0, "ambiguates built-in declaration %q#D", - olddecl); + warning ("new declaration `%#D'", newdecl); + warning ("ambiguates built-in declaration `%#D'", + olddecl); } - else - warning (OPT_Wshadow, "shadowing %s function %q#D", - DECL_BUILT_IN (olddecl) ? "built-in" : "library", - olddecl); + else if (warn_shadow) + warning ("shadowing %s function `%#D'", + DECL_BUILT_IN (olddecl) ? "built-in" : "library", + olddecl); } else /* Discard the old built-in function. */ return NULL_TREE; /* Replace the old RTL to avoid problems with inlining. */ - COPY_DECL_RTL (newdecl, olddecl); + SET_DECL_RTL (olddecl, DECL_RTL (newdecl)); } - /* Even if the types match, prefer the new declarations type for - built-ins which have not been explicitly declared, for - exception lists, etc... */ + /* Even if the types match, prefer the new declarations type + for anticipated built-ins, for exception lists, etc... */ else if (DECL_ANTICIPATED (olddecl)) { tree type = TREE_TYPE (newdecl); @@ -1288,7 +1289,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) that all remnants of the builtin-ness of this function will be banished. */ SET_DECL_LANGUAGE (olddecl, DECL_LANGUAGE (newdecl)); - COPY_DECL_RTL (newdecl, olddecl); + SET_DECL_RTL (olddecl, DECL_RTL (newdecl)); } } else if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) @@ -1317,12 +1318,15 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) && DECL_FUNCTION_TEMPLATE_P (newdecl))) return NULL_TREE; - error ("%q#D redeclared as different kind of symbol", newdecl); + error ("`%#D' redeclared as different kind of symbol", newdecl); if (TREE_CODE (olddecl) == TREE_LIST) olddecl = TREE_VALUE (olddecl); - error ("previous declaration of %q+#D", olddecl); + cp_error_at ("previous declaration of `%#D'", olddecl); - return error_mark_node; + /* New decl is completely inconsistent with the old one => + tell caller to replace the old one. */ + + return NULL_TREE; } else if (!types_match) { @@ -1339,8 +1343,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == TYPE_DECL || TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) { - error ("declaration of template %q#D", newdecl); - error ("conflicts with previous declaration %q+#D", olddecl); + error ("declaration of template `%#D'", newdecl); + cp_error_at ("conflicts with previous declaration `%#D'", + olddecl); } else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL @@ -1353,8 +1358,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)), TREE_TYPE (TREE_TYPE (olddecl)))) { - error ("new declaration %q#D", newdecl); - error ("ambiguates old declaration %q+#D", olddecl); + error ("new declaration `%#D'", newdecl); + cp_error_at ("ambiguates old declaration `%#D'", olddecl); } return NULL_TREE; } @@ -1362,25 +1367,25 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) { if (DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl)) { - error ("declaration of C function %q#D conflicts with", - newdecl); - error ("previous declaration %q+#D here", olddecl); + error ("declaration of C function `%#D' conflicts with", + newdecl); + cp_error_at ("previous declaration `%#D' here", olddecl); } else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), TYPE_ARG_TYPES (TREE_TYPE (olddecl)))) { - error ("new declaration %q#D", newdecl); - error ("ambiguates old declaration %q+#D", olddecl); - return error_mark_node; + error ("new declaration `%#D'", newdecl); + cp_error_at ("ambiguates old declaration `%#D'", olddecl); } else return NULL_TREE; } else { - error ("conflicting declaration %q#D", newdecl); - error ("%q+D has a previous declaration as %q#D", olddecl, olddecl); - return error_mark_node; + error ("conflicting declaration '%#D'", newdecl); + cp_error_at ("'%D' has a previous declaration as `%#D'", + olddecl, olddecl); + return NULL_TREE; } } else if (TREE_CODE (newdecl) == FUNCTION_DECL @@ -1412,27 +1417,27 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) else if (TREE_CODE (newdecl) == NAMESPACE_DECL) { /* In [namespace.alias] we have: - - In a declarative region, a namespace-alias-definition can be + + In a declarative region, a namespace-alias-definition can be used to redefine a namespace-alias declared in that declarative region to refer only to the namespace to which it already refers. - + Therefore, if we encounter a second alias directive for the same alias, we can just ignore the second directive. */ if (DECL_NAMESPACE_ALIAS (newdecl) - && (DECL_NAMESPACE_ALIAS (newdecl) + && (DECL_NAMESPACE_ALIAS (newdecl) == DECL_NAMESPACE_ALIAS (olddecl))) return olddecl; /* [namespace.alias] - A namespace-name or namespace-alias shall not be declared as + A namespace-name or namespace-alias shall not be declared as the name of any other entity in the same declarative region. A namespace-name defined at global scope shall not be - declared as the name of any other entity in any global scope + declared as the name of any other entity in any glogal scope of the program. */ - error ("declaration of namespace %qD conflicts with", newdecl); - error ("previous declaration of namespace %q+D here", olddecl); + error ("declaration of `namespace %D' conflicts with", newdecl); + cp_error_at ("previous declaration of `namespace %D' here", olddecl); return error_mark_node; } else @@ -1442,9 +1447,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) { error (errmsg, newdecl); if (DECL_NAME (olddecl) != NULL_TREE) - error ((DECL_INITIAL (olddecl) && namespace_bindings_p ()) - ? "%q+#D previously defined here" - : "%q+#D previously declared here", olddecl); + cp_error_at ((DECL_INITIAL (olddecl) + && namespace_bindings_p ()) + ? "`%#D' previously defined here" + : "`%#D' previously declared here", olddecl); return error_mark_node; } else if (TREE_CODE (olddecl) == FUNCTION_DECL @@ -1453,51 +1459,23 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != NULL_TREE) { /* Prototype decl follows defn w/o prototype. */ - warning (0, "prototype for %q+#D", newdecl); - warning (0, "%Jfollows non-prototype definition here", olddecl); + cp_warning_at ("prototype for `%#D'", newdecl); + warning ("%Jfollows non-prototype definition here", olddecl); } - else if ((TREE_CODE (olddecl) == FUNCTION_DECL - || TREE_CODE (olddecl) == VAR_DECL) + else if (TREE_CODE (olddecl) == FUNCTION_DECL && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl)) { - /* [dcl.link] - If two declarations of the same function or object - specify different linkage-specifications ..., the program - is ill-formed.... Except for functions with C++ linkage, - a function declaration without a linkage specification - shall not precede the first linkage specification for - that function. A function can be declared without a - linkage specification after an explicit linkage - specification has been seen; the linkage explicitly - specified in the earlier declaration is not affected by - such a function declaration. - - DR 563 raises the question why the restrictions on - functions should not also apply to objects. Older - versions of G++ silently ignore the linkage-specification - for this example: - - namespace N { - extern int i; - extern "C" int i; - } - - which is clearly wrong. Therefore, we now treat objects - like functions. */ + /* extern "C" int foo (); + int foo () { bar (); } + is OK. */ if (current_lang_depth () == 0) - { - /* There is no explicit linkage-specification, so we use - the linkage from the previous declaration. */ - if (!DECL_LANG_SPECIFIC (newdecl)) - retrofit_lang_decl (newdecl); - SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl)); - } + SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl)); else { - error ("previous declaration of %q+#D with %qL linkage", - olddecl, DECL_LANGUAGE (olddecl)); - error ("conflicts with new declaration with %qL linkage", - DECL_LANGUAGE (newdecl)); + cp_error_at ("previous declaration of `%#D' with %L linkage", + olddecl, DECL_LANGUAGE (olddecl)); + error ("conflicts with new declaration with %L linkage", + DECL_LANGUAGE (newdecl)); } } @@ -1519,25 +1497,26 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (1 == simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))) { - pedwarn ("default argument given for parameter %d of %q#D", + pedwarn ("default argument given for parameter %d of `%#D'", i, newdecl); - pedwarn ("after previous specification in %q+#D", olddecl); + cp_pedwarn_at ("after previous specification in `%#D'", + olddecl); } else { - error ("default argument given for parameter %d of %q#D", - i, newdecl); - error ("after previous specification in %q+#D", + error ("default argument given for parameter %d of `%#D'", + i, newdecl); + cp_error_at ("after previous specification in `%#D'", olddecl); } } - if (DECL_DECLARED_INLINE_P (newdecl) + if (DECL_DECLARED_INLINE_P (newdecl) && ! DECL_DECLARED_INLINE_P (olddecl) && TREE_ADDRESSABLE (olddecl) && warn_inline) { - warning (0, "%q#D was used before it was declared inline", newdecl); - warning (0, "%Jprevious non-inline declaration here", olddecl); + warning ("`%#D' was used before it was declared inline", newdecl); + warning ("%Jprevious non-inline declaration here", olddecl); } } } @@ -1573,6 +1552,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); DECL_PURE_VIRTUAL_P (newdecl) |= DECL_PURE_VIRTUAL_P (olddecl); DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl); + DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl); DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl); if (DECL_OVERLOADED_OPERATOR_P (olddecl) != ERROR_MARK) SET_OVERLOADED_OPERATOR_CODE @@ -1580,17 +1560,17 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE; /* Optionally warn about more than one declaration for the same - name, but don't warn about a function declaration followed by a - definition. */ + name, but don't warn about a function declaration followed by a + definition. */ if (warn_redundant_decls && ! DECL_ARTIFICIAL (olddecl) && !(new_defines_function && DECL_INITIAL (olddecl) == NULL_TREE) /* Don't warn about extern decl followed by definition. */ && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl)) /* Don't warn about friends, let add_friend take care of it. */ - && ! (newdecl_is_friend || DECL_FRIEND_P (olddecl))) + && ! (DECL_FRIEND_P (newdecl) || DECL_FRIEND_P (olddecl))) { - warning (OPT_Wredundant_decls, "redundant redeclaration of %qD in same scope", newdecl); - warning (OPT_Wredundant_decls, "previous declaration of %q+D", olddecl); + warning ("redundant redeclaration of `%D' in same scope", newdecl); + cp_warning_at ("previous declaration of `%D'", olddecl); } } @@ -1615,35 +1595,30 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (TREE_CODE (newdecl) == TEMPLATE_DECL) { - tree old_result; - tree new_result; - old_result = DECL_TEMPLATE_RESULT (olddecl); - new_result = DECL_TEMPLATE_RESULT (newdecl); - TREE_TYPE (olddecl) = TREE_TYPE (old_result); + TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)); DECL_TEMPLATE_SPECIALIZATIONS (olddecl) = chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl), DECL_TEMPLATE_SPECIALIZATIONS (newdecl)); - if (DECL_FUNCTION_TEMPLATE_P (newdecl)) - { - DECL_INLINE (old_result) - |= DECL_INLINE (new_result); - DECL_DECLARED_INLINE_P (old_result) - |= DECL_DECLARED_INLINE_P (new_result); - check_redeclaration_exception_specification (newdecl, olddecl); - } - /* If the new declaration is a definition, update the file and line information on the declaration. */ - if (DECL_INITIAL (old_result) == NULL_TREE - && DECL_INITIAL (new_result) != NULL_TREE) + if (DECL_INITIAL (DECL_TEMPLATE_RESULT (olddecl)) == NULL_TREE + && DECL_INITIAL (DECL_TEMPLATE_RESULT (newdecl)) != NULL_TREE) { - DECL_SOURCE_LOCATION (olddecl) - = DECL_SOURCE_LOCATION (old_result) + DECL_SOURCE_LOCATION (olddecl) + = DECL_SOURCE_LOCATION (DECL_TEMPLATE_RESULT (olddecl)) = DECL_SOURCE_LOCATION (newdecl); if (DECL_FUNCTION_TEMPLATE_P (newdecl)) - DECL_ARGUMENTS (old_result) - = DECL_ARGUMENTS (new_result); + DECL_ARGUMENTS (DECL_TEMPLATE_RESULT (olddecl)) + = DECL_ARGUMENTS (DECL_TEMPLATE_RESULT (newdecl)); + } + + if (DECL_FUNCTION_TEMPLATE_P (newdecl)) + { + DECL_INLINE (DECL_TEMPLATE_RESULT (olddecl)) + |= DECL_INLINE (DECL_TEMPLATE_RESULT (newdecl)); + DECL_DECLARED_INLINE_P (DECL_TEMPLATE_RESULT (olddecl)) + |= DECL_DECLARED_INLINE_P (DECL_TEMPLATE_RESULT (newdecl)); } return olddecl; @@ -1667,33 +1642,34 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) { DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl); DECL_INITIALIZED_P (newdecl) |= DECL_INITIALIZED_P (olddecl); - DECL_NONTRIVIALLY_INITIALIZED_P (newdecl) - |= DECL_NONTRIVIALLY_INITIALIZED_P (olddecl); DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (newdecl) |= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl); - - /* Merge the threadprivate attribute from OLDDECL into NEWDECL. */ - if (DECL_LANG_SPECIFIC (olddecl) - && CP_DECL_THREADPRIVATE_P (olddecl)) - { - /* Allocate a LANG_SPECIFIC structure for NEWDECL, if needed. */ - if (!DECL_LANG_SPECIFIC (newdecl)) - retrofit_lang_decl (newdecl); - - DECL_TLS_MODEL (newdecl) = DECL_TLS_MODEL (olddecl); - CP_DECL_THREADPRIVATE_P (newdecl) = 1; - } } /* Do this after calling `merge_types' so that default parameters don't confuse us. */ - else if (TREE_CODE (newdecl) == FUNCTION_DECL) - check_redeclaration_exception_specification (newdecl, olddecl); + else if (TREE_CODE (newdecl) == FUNCTION_DECL + && (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)) + != TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl)))) + { + TREE_TYPE (newdecl) = build_exception_variant (newtype, + TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl))); + TREE_TYPE (olddecl) = build_exception_variant (newtype, + TYPE_RAISES_EXCEPTIONS (oldtype)); + + if ((pedantic || ! DECL_IN_SYSTEM_HEADER (olddecl)) + && DECL_SOURCE_LINE (olddecl) != 0 + && flag_exceptions + && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)), + TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl)), 1)) + { + error ("declaration of `%F' throws different exceptions", + newdecl); + cp_error_at ("than previous declaration `%F'", olddecl); + } + } TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype; - if (TREE_CODE (newdecl) == FUNCTION_DECL) - check_default_args (newdecl); - /* Lay the type out, unless already done. */ if (! same_type_p (newtype, oldtype) && TREE_TYPE (newdecl) != error_mark_node @@ -1713,12 +1689,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) TREE_READONLY (olddecl) = 1; if (TREE_THIS_VOLATILE (newdecl)) TREE_THIS_VOLATILE (olddecl) = 1; - if (TREE_NOTHROW (newdecl)) - TREE_NOTHROW (olddecl) = 1; - - /* Merge deprecatedness. */ - if (TREE_DEPRECATED (newdecl)) - TREE_DEPRECATED (olddecl) = 1; /* Merge the initialization information. */ if (DECL_INITIAL (newdecl) == NULL_TREE @@ -1731,12 +1701,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) && DECL_LANG_SPECIFIC (olddecl)) { DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl); - DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl); + DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl); } } /* Merge the section attribute. - We want to issue an error if the sections conflict but that must be + We want to issue an error if the sections conflict but that must be done later in decl_attributes since we are called before attributes are assigned. */ if (DECL_SECTION_NAME (newdecl) == NULL_TREE) @@ -1755,7 +1725,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) /* Keep the old RTL. */ COPY_DECL_RTL (olddecl, newdecl); } - else if (TREE_CODE (newdecl) == VAR_DECL + else if (TREE_CODE (newdecl) == VAR_DECL && (DECL_SIZE (olddecl) || !DECL_SIZE (newdecl))) { /* Keep the old RTL. We cannot keep the old RTL if the old @@ -1790,7 +1760,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (! DECL_EXTERNAL (olddecl)) DECL_EXTERNAL (newdecl) = 0; - new_template = NULL_TREE; if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl)) { DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl); @@ -1798,30 +1767,16 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl); DECL_TEMPLATE_INSTANTIATED (newdecl) |= DECL_TEMPLATE_INSTANTIATED (olddecl); - - /* If the OLDDECL is an instantiation and/or specialization, - then the NEWDECL must be too. But, it may not yet be marked - as such if the caller has created NEWDECL, but has not yet - figured out that it is a redeclaration. */ - if (!DECL_USE_TEMPLATE (newdecl)) - DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl); - /* Don't really know how much of the language-specific values we should copy from old to new. */ DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl); - DECL_LANG_SPECIFIC (newdecl)->decl_flags.u2 = + DECL_LANG_SPECIFIC (newdecl)->decl_flags.u2 = DECL_LANG_SPECIFIC (olddecl)->decl_flags.u2; DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl); - DECL_REPO_AVAILABLE_P (newdecl) = DECL_REPO_AVAILABLE_P (olddecl); - if (DECL_TEMPLATE_INFO (newdecl)) - new_template = DECL_TI_TEMPLATE (newdecl); DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); DECL_INITIALIZED_IN_CLASS_P (newdecl) - |= DECL_INITIALIZED_IN_CLASS_P (olddecl); + |= DECL_INITIALIZED_IN_CLASS_P (olddecl); olddecl_friend = DECL_FRIEND_P (olddecl); - hidden_friend = (DECL_ANTICIPATED (olddecl) - && DECL_HIDDEN_FRIEND_P (olddecl) - && newdecl_is_friend); /* Only functions have DECL_BEFRIENDING_CLASSES. */ if (TREE_CODE (newdecl) == FUNCTION_DECL @@ -1845,7 +1800,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) /* If newdecl is not a specialization, then it is not a template-related function at all. And that means that we should have exited above, returning 0. */ - gcc_assert (DECL_TEMPLATE_SPECIALIZATION (newdecl)); + my_friendly_assert (DECL_TEMPLATE_SPECIALIZATION (newdecl), + 0); if (TREE_USED (olddecl)) /* From [temp.expl.spec]: @@ -1856,16 +1812,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs. */ - error ("explicit specialization of %qD after first use", + error ("explicit specialization of %D after first use", olddecl); SET_DECL_TEMPLATE_SPECIALIZATION (olddecl); - /* Don't propagate visibility from the template to the - specialization here. We'll do that in determine_visibility if - appropriate. */ - DECL_VISIBILITY_SPECIFIED (olddecl) = 0; - /* [temp.expl.spec/14] We don't inline explicit specialization just because the primary template says so. */ } @@ -1876,7 +1827,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) DECL_DECLARED_INLINE_P (newdecl) |= DECL_DECLARED_INLINE_P (olddecl); - /* If either decl says `inline', this fn is inline, unless + /* If either decl says `inline', this fn is inline, unless its definition was passed already. */ if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == NULL_TREE) DECL_INLINE (olddecl) = 1; @@ -1893,7 +1844,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) { SET_DECL_LANGUAGE (olddecl, DECL_LANGUAGE (newdecl)); COPY_DECL_ASSEMBLER_NAME (newdecl, olddecl); - COPY_DECL_RTL (newdecl, olddecl); + SET_DECL_RTL (olddecl, DECL_RTL (newdecl)); } if (! types_match || new_defines_function) { @@ -1917,7 +1868,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); /* If we're keeping the built-in definition, keep the rtl, regardless of declaration matches. */ - COPY_DECL_RTL (olddecl, newdecl); + SET_DECL_RTL (newdecl, DECL_RTL (olddecl)); } DECL_RESULT (newdecl) = DECL_RESULT (olddecl); @@ -1935,53 +1886,30 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) DECL_COMMON (newdecl) = DECL_COMMON (olddecl); COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); - /* Warn about conflicting visibility specifications. */ - if (DECL_VISIBILITY_SPECIFIED (olddecl) - && DECL_VISIBILITY_SPECIFIED (newdecl) - && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) - { - warning (OPT_Wattributes, "%q+D: visibility attribute ignored " - "because it", newdecl); - warning (OPT_Wattributes, "%Jconflicts with previous " - "declaration here", olddecl); - } - /* Choose the declaration which specified visibility. */ - if (DECL_VISIBILITY_SPECIFIED (olddecl)) + /* If either declaration has a nondefault visibility, use it. */ + if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT) { + if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT + && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) + { + warning ("%J'%D': visibility attribute ignored because it", + newdecl, newdecl); + warning ("%Jconflicts with previous declaration here", olddecl); + } DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); - DECL_VISIBILITY_SPECIFIED (newdecl) = 1; - } - /* Init priority used to be merged from newdecl to olddecl by the memcpy, - so keep this behavior. */ - if (TREE_CODE (newdecl) == VAR_DECL && DECL_HAS_INIT_PRIORITY_P (newdecl)) - { - SET_DECL_INIT_PRIORITY (olddecl, DECL_INIT_PRIORITY (newdecl)); - DECL_HAS_INIT_PRIORITY_P (olddecl) = 1; - } - - /* The DECL_LANG_SPECIFIC information in OLDDECL will be replaced - with that from NEWDECL below. */ - if (DECL_LANG_SPECIFIC (olddecl)) - { - gcc_assert (DECL_LANG_SPECIFIC (olddecl) - != DECL_LANG_SPECIFIC (newdecl)); - ggc_free (DECL_LANG_SPECIFIC (olddecl)); } if (TREE_CODE (newdecl) == FUNCTION_DECL) { int function_size; - function_size = sizeof (struct tree_decl_common); + function_size = sizeof (struct tree_decl); memcpy ((char *) olddecl + sizeof (struct tree_common), (char *) newdecl + sizeof (struct tree_common), function_size - sizeof (struct tree_common)); - memcpy ((char *) olddecl + sizeof (struct tree_decl_common), - (char *) newdecl + sizeof (struct tree_decl_common), - sizeof (struct tree_function_decl) - sizeof (struct tree_decl_common)); - if (new_template) + if (DECL_TEMPLATE_INSTANTIATION (newdecl)) /* If newdecl is a template instantiation, it is possible that the following sequence of events has occurred: @@ -2003,48 +1931,21 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) olddecl, and not newdecl, is on the list of instantiations so that if we try to do the instantiation again we won't get the clobbered declaration. */ - reregister_specialization (newdecl, - new_template, + reregister_specialization (newdecl, + DECL_TI_TEMPLATE (newdecl), olddecl); } else { - size_t size = tree_code_size (TREE_CODE (olddecl)); memcpy ((char *) olddecl + sizeof (struct tree_common), (char *) newdecl + sizeof (struct tree_common), - sizeof (struct tree_decl_common) - sizeof (struct tree_common)); - switch (TREE_CODE (olddecl)) - { - case LABEL_DECL: - case VAR_DECL: - case RESULT_DECL: - case PARM_DECL: - case FIELD_DECL: - case TYPE_DECL: - case CONST_DECL: - { - memcpy ((char *) olddecl + sizeof (struct tree_decl_common), - (char *) newdecl + sizeof (struct tree_decl_common), - size - sizeof (struct tree_decl_common) - + TREE_CODE_LENGTH (TREE_CODE (newdecl)) * sizeof (char *)); - } - break; - default: - memcpy ((char *) olddecl + sizeof (struct tree_decl_common), - (char *) newdecl + sizeof (struct tree_decl_common), - sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common) - + TREE_CODE_LENGTH (TREE_CODE (newdecl)) * sizeof (char *)); - break; - } + sizeof (struct tree_decl) - sizeof (struct tree_common) + + TREE_CODE_LENGTH (TREE_CODE (newdecl)) * sizeof (char *)); } + DECL_UID (olddecl) = olddecl_uid; if (olddecl_friend) DECL_FRIEND_P (olddecl) = 1; - if (hidden_friend) - { - DECL_ANTICIPATED (olddecl) = 1; - DECL_HIDDEN_FRIEND_P (olddecl) = 1; - } /* NEWDECL contains the merged attribute lists. Update OLDDECL to be the same. */ @@ -2053,20 +1954,48 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl so that encode_section_info has a chance to look at the new decl flags and attributes. */ - if (DECL_RTL_SET_P (olddecl) + if (DECL_RTL_SET_P (olddecl) && (TREE_CODE (olddecl) == FUNCTION_DECL || (TREE_CODE (olddecl) == VAR_DECL && TREE_STATIC (olddecl)))) - make_decl_rtl (olddecl); - - /* The NEWDECL will no longer be needed. Because every out-of-class - declaration of a member results in a call to duplicate_decls, - freeing these nodes represents in a significant savings. */ - ggc_free (newdecl); + make_decl_rtl (olddecl, NULL); return olddecl; } +/* Generate an implicit declaration for identifier FUNCTIONID + as a function of type int (). Print a warning if appropriate. */ + +tree +implicitly_declare (tree functionid) +{ + tree decl; + + /* We used to reuse an old implicit decl here, + but this loses with inline functions because it can clobber + the saved decl chains. */ + decl = build_lang_decl (FUNCTION_DECL, functionid, default_function_type); + + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + + /* ISO standard says implicit declarations are in the innermost block. + So we record the decl in the standard fashion. */ + pushdecl (decl); + rest_of_decl_compilation (decl, NULL, 0, 0); + + if (warn_implicit + /* Only one warning per identifier. */ + && IDENTIFIER_IMPLICIT_DECL (functionid) == NULL_TREE) + { + pedwarn ("implicit declaration of function `%#D'", decl); + } + + SET_IDENTIFIER_IMPLICIT_DECL (functionid, decl); + + return decl; +} + /* Return zero if the declaration NEWDECL is valid when the declaration OLDDECL (assumed to be for the same name) has already been seen. @@ -2082,39 +2011,38 @@ redeclaration_error_message (tree newdecl, tree olddecl) constructs like "typedef struct foo { ... } foo" would look like an erroneous redeclaration. */ if (same_type_p (TREE_TYPE (newdecl), TREE_TYPE (olddecl))) - return NULL; + return 0; else - return "redefinition of %q#D"; + return "redefinition of `%#D'"; } else if (TREE_CODE (newdecl) == FUNCTION_DECL) { /* If this is a pure function, its olddecl will actually be the original initialization to `0' (which we force to call abort()). Don't complain about redefinition in this case. */ - if (DECL_LANG_SPECIFIC (olddecl) && DECL_PURE_VIRTUAL_P (olddecl) - && DECL_INITIAL (olddecl) == NULL_TREE) - return NULL; + if (DECL_LANG_SPECIFIC (olddecl) && DECL_PURE_VIRTUAL_P (olddecl)) + return 0; /* If both functions come from different namespaces, this is not a redeclaration - this is a conflict with a used function. */ if (DECL_NAMESPACE_SCOPE_P (olddecl) && DECL_CONTEXT (olddecl) != DECL_CONTEXT (newdecl) && ! decls_match (olddecl, newdecl)) - return "%qD conflicts with used function"; + return "`%D' conflicts with used function"; /* We'll complain about linkage mismatches in - warn_extern_redeclared_static. */ + warn_extern_redeclared_static. */ /* Defining the same name twice is no good. */ if (DECL_INITIAL (olddecl) != NULL_TREE && DECL_INITIAL (newdecl) != NULL_TREE) { if (DECL_NAME (olddecl) == NULL_TREE) - return "%q#D not declared in class"; + return "`%#D' not declared in class"; else - return "redefinition of %q#D"; + return "redefinition of `%#D'"; } - return NULL; + return 0; } else if (TREE_CODE (newdecl) == TEMPLATE_DECL) { @@ -2124,12 +2052,12 @@ redeclaration_error_message (tree newdecl, tree olddecl) { if (COMPLETE_TYPE_P (TREE_TYPE (newdecl)) && COMPLETE_TYPE_P (TREE_TYPE (olddecl))) - return "redefinition of %q#D"; + return "redefinition of `%#D'"; return NULL; } if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) != FUNCTION_DECL - || (DECL_TEMPLATE_RESULT (newdecl) + || (DECL_TEMPLATE_RESULT (newdecl) == DECL_TEMPLATE_RESULT (olddecl))) return NULL; @@ -2140,33 +2068,18 @@ redeclaration_error_message (tree newdecl, tree olddecl) if (DECL_TEMPLATE_INFO (ot)) ot = DECL_TEMPLATE_RESULT (template_for_substitution (ot)); if (DECL_INITIAL (nt) && DECL_INITIAL (ot)) - return "redefinition of %q#D"; + return "redefinition of `%#D'"; return NULL; } - else if (TREE_CODE (newdecl) == VAR_DECL - && DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl) - && (! DECL_LANG_SPECIFIC (olddecl) - || ! CP_DECL_THREADPRIVATE_P (olddecl) - || DECL_THREAD_LOCAL_P (newdecl))) - { - /* Only variables can be thread-local, and all declarations must - agree on this property. */ - if (DECL_THREAD_LOCAL_P (newdecl)) - return "thread-local declaration of %q#D follows " - "non-thread-local declaration"; - else - return "non-thread-local declaration of %q#D follows " - "thread-local declaration"; - } else if (toplevel_bindings_p () || DECL_NAMESPACE_SCOPE_P (newdecl)) { /* Objects declared at top level: */ /* If at least one is a reference, it's ok. */ if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl)) - return NULL; + return 0; /* Reject two definitions. */ - return "redefinition of %q#D"; + return "redefinition of `%#D'"; } else { @@ -2174,35 +2087,16 @@ redeclaration_error_message (tree newdecl, tree olddecl) /* Reject two definitions, and reject a definition together with an external reference. */ if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl))) - return "redeclaration of %q#D"; - return NULL; + return "redeclaration of `%#D'"; + return 0; } } -/* Hash and equality functions for the named_label table. */ - -static hashval_t -named_label_entry_hash (const void *data) -{ - const struct named_label_entry *ent = (const struct named_label_entry *) data; - return DECL_UID (ent->label_decl); -} - -static int -named_label_entry_eq (const void *a, const void *b) -{ - const struct named_label_entry *ent_a = (const struct named_label_entry *) a; - const struct named_label_entry *ent_b = (const struct named_label_entry *) b; - return ent_a->label_decl == ent_b->label_decl; -} - /* Create a new label, named ID. */ static tree make_label_decl (tree id, int local_p) { - struct named_label_entry *ent; - void **slot; tree decl; decl = build_decl (LABEL_DECL, id, void_type_node); @@ -2218,22 +2112,30 @@ make_label_decl (tree id, int local_p) /* Record the fact that this identifier is bound to this label. */ SET_IDENTIFIER_LABEL_VALUE (id, decl); - /* Create the label htab for the function on demand. */ - if (!named_labels) - named_labels = htab_create_ggc (13, named_label_entry_hash, - named_label_entry_eq, NULL); - - /* Record this label on the list of labels used in this function. - We do this before calling make_label_decl so that we get the - IDENTIFIER_LABEL_VALUE before the new label is declared. */ - ent = GGC_CNEW (struct named_label_entry); - ent->label_decl = decl; + return decl; +} - slot = htab_find_slot (named_labels, ent, INSERT); - gcc_assert (*slot == NULL); - *slot = ent; +/* Record this label on the list of used labels so that we can check + at the end of the function to see whether or not the label was + actually defined, and so we can check when the label is defined whether + this use is valid. */ - return decl; +static void +use_label (tree decl) +{ + if (named_label_uses == NULL + || named_label_uses->names_in_scope != current_binding_level->names + || named_label_uses->label_decl != decl) + { + struct named_label_use_list *new_ent; + new_ent = ggc_alloc (sizeof (struct named_label_use_list)); + new_ent->label_decl = decl; + new_ent->names_in_scope = current_binding_level->names; + new_ent->binding_level = current_binding_level; + new_ent->o_goto_locus = input_location; + new_ent->next = named_label_uses; + named_label_uses = new_ent; + } } /* Look for a label named ID in the current function. If one cannot @@ -2244,12 +2146,14 @@ tree lookup_label (tree id) { tree decl; + struct named_label_list *ent; timevar_push (TV_NAME_LOOKUP); /* You can't use labels at global scope. */ if (current_function_decl == NULL_TREE) { - error ("label %qE referenced outside of any function", id); + error ("label `%s' referenced outside of any function", + IDENTIFIER_POINTER (id)); POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE); } @@ -2258,7 +2162,20 @@ lookup_label (tree id) if (decl != NULL_TREE && DECL_CONTEXT (decl) == current_function_decl) POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl); + /* Record this label on the list of labels used in this function. + We do this before calling make_label_decl so that we get the + IDENTIFIER_LABEL_VALUE before the new label is declared. */ + ent = ggc_alloc_cleared (sizeof (struct named_label_list)); + ent->old_value = IDENTIFIER_LABEL_VALUE (id); + ent->next = named_labels; + named_labels = ent; + + /* We need a new label. */ decl = make_label_decl (id, /*local_p=*/0); + + /* Now fill in the information we didn't have before. */ + ent->label_decl = decl; + POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl); } @@ -2267,16 +2184,18 @@ lookup_label (tree id) tree declare_local_label (tree id) { - tree decl, shadow; + tree decl; /* Add a new entry to the SHADOWED_LABELS list so that when we leave - this scope we can restore the old value of IDENTIFIER_TYPE_VALUE. */ - shadow = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE, - current_binding_level->shadowed_labels); - current_binding_level->shadowed_labels = shadow; - + this scope we can restore the old value of + IDENTIFIER_TYPE_VALUE. */ + current_binding_level->shadowed_labels + = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE, + current_binding_level->shadowed_labels); + /* Look for the label. */ decl = make_label_decl (id, /*local_p=*/1); - TREE_VALUE (shadow) = decl; + /* Now fill in the information we didn't have before. */ + TREE_VALUE (current_binding_level->shadowed_labels) = decl; return decl; } @@ -2287,119 +2206,125 @@ declare_local_label (tree id) static int decl_jump_unsafe (tree decl) { - if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl) - || TREE_TYPE (decl) == error_mark_node) + if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl)) return 0; - if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)) - || DECL_NONTRIVIALLY_INITIALIZED_P (decl)) - return 2; - - if (pod_type_p (TREE_TYPE (decl))) + if (DECL_INITIAL (decl) == NULL_TREE + && pod_type_p (TREE_TYPE (decl))) return 0; - /* The POD stuff is just pedantry; why should it matter if the class + /* This is really only important if we're crossing an initialization. + The POD stuff is just pedantry; why should it matter if the class contains a field of pointer to member type? */ + if (DECL_INITIAL (decl) + || (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))) + return 2; return 1; } -/* A subroutine of check_previous_goto_1 to identify a branch to the user. */ - -static void -identify_goto (tree decl, const location_t *locus) -{ - if (decl) - pedwarn ("jump to label %qD", decl); - else - pedwarn ("jump to case label"); - if (locus) - pedwarn ("%H from here", locus); -} - /* Check that a single previously seen jump to a newly defined label is OK. DECL is the LABEL_DECL or 0; LEVEL is the binding_level for the jump context; NAMES are the names in scope in LEVEL at the jump - context; LOCUS is the source position of the jump or 0. Returns - true if all is well. */ - -static bool -check_previous_goto_1 (tree decl, struct cp_binding_level* level, tree names, - bool exited_omp, const location_t *locus) -{ - struct cp_binding_level *b; - bool identified = false, saw_eh = false, saw_omp = false; + context; FILE and LINE are the source position of the jump or 0. */ - if (exited_omp) - { - identify_goto (decl, locus); - error (" exits OpenMP structured block"); - identified = saw_omp = true; - } - - for (b = current_binding_level; b ; b = b->level_chain) - { - tree new_decls, old_decls = (b == level ? names : NULL_TREE); - - for (new_decls = b->names; new_decls != old_decls; +static void +check_previous_goto_1 (tree decl, + struct cp_binding_level* level, + tree names, const location_t *locus) +{ + int identified = 0; + int saw_eh = 0; + struct cp_binding_level *b = current_binding_level; + for (; b; b = b->level_chain) + { + tree new_decls = b->names; + tree old_decls = (b == level ? names : NULL_TREE); + for (; new_decls != old_decls; new_decls = TREE_CHAIN (new_decls)) { int problem = decl_jump_unsafe (new_decls); if (! problem) continue; - if (!identified) + if (! identified) { - identify_goto (decl, locus); - identified = true; + if (decl) + pedwarn ("jump to label `%D'", decl); + else + pedwarn ("jump to case label"); + + if (locus) + pedwarn ("%H from here", locus); + identified = 1; } + if (problem > 1) - error (" crosses initialization of %q+#D", new_decls); + cp_error_at (" crosses initialization of `%#D'", + new_decls); else - pedwarn (" enters scope of non-POD %q+#D", new_decls); + cp_pedwarn_at (" enters scope of non-POD `%#D'", + new_decls); } if (b == level) break; - if ((b->kind == sk_try || b->kind == sk_catch) && !saw_eh) + if ((b->kind == sk_try || b->kind == sk_catch) && ! saw_eh) { - if (!identified) + if (! identified) { - identify_goto (decl, locus); - identified = true; + if (decl) + pedwarn ("jump to label `%D'", decl); + else + pedwarn ("jump to case label"); + + if (locus) + pedwarn ("%H from here", locus); + identified = 1; } if (b->kind == sk_try) error (" enters try block"); else error (" enters catch block"); - saw_eh = true; - } - if (b->kind == sk_omp && !saw_omp) - { - if (!identified) - { - identify_goto (decl, locus); - identified = true; - } - error (" enters OpenMP structured block"); - saw_omp = true; + saw_eh = 1; } } - - return !identified; } static void -check_previous_goto (tree decl, struct named_label_use_entry *use) +check_previous_goto (struct named_label_use_list* use) { - check_previous_goto_1 (decl, use->binding_level, - use->names_in_scope, use->in_omp_scope, - &use->o_goto_locus); + check_previous_goto_1 (use->label_decl, use->binding_level, + use->names_in_scope, &use->o_goto_locus); } -static bool +static void check_switch_goto (struct cp_binding_level* level) { - return check_previous_goto_1 (NULL_TREE, level, level->names, false, NULL); + check_previous_goto_1 (NULL_TREE, level, level->names, NULL); +} + +/* Check that any previously seen jumps to a newly defined label DECL + are OK. Called by define_label. */ + +static void +check_previous_gotos (tree decl) +{ + struct named_label_use_list **usep; + + if (! TREE_USED (decl)) + return; + + for (usep = &named_label_uses; *usep; ) + { + struct named_label_use_list *use = *usep; + if (use->label_decl == decl) + { + check_previous_goto (use); + *usep = use->next; + } + else + usep = &(use->next); + } } /* Check that a new jump to a label DECL is OK. Called by @@ -2408,114 +2333,57 @@ check_switch_goto (struct cp_binding_level* level) void check_goto (tree decl) { - struct named_label_entry *ent, dummy; - bool saw_catch = false, identified = false; + int identified = 0; tree bad; + struct named_label_list *lab; - /* We can't know where a computed goto is jumping. - So we assume that it's OK. */ - if (TREE_CODE (decl) != LABEL_DECL) - return; - - /* We didn't record any information about this label when we created it, - and there's not much point since it's trivial to analyze as a return. */ - if (decl == cdtor_label) + /* We can't know where a computed goto is jumping. So we assume + that it's OK. */ + if (! DECL_P (decl)) return; - dummy.label_decl = decl; - ent = (struct named_label_entry *) htab_find (named_labels, &dummy); - gcc_assert (ent != NULL); - /* If the label hasn't been defined yet, defer checking. */ if (! DECL_INITIAL (decl)) { - struct named_label_use_entry *new_use; - - /* Don't bother creating another use if the last goto had the - same data, and will therefore create the same set of errors. */ - if (ent->uses - && ent->uses->names_in_scope == current_binding_level->names) - return; - - new_use = GGC_NEW (struct named_label_use_entry); - new_use->binding_level = current_binding_level; - new_use->names_in_scope = current_binding_level->names; - new_use->o_goto_locus = input_location; - new_use->in_omp_scope = false; - - new_use->next = ent->uses; - ent->uses = new_use; + use_label (decl); return; } - if (ent->in_try_scope || ent->in_catch_scope - || ent->in_omp_scope || ent->bad_decls) + for (lab = named_labels; lab; lab = lab->next) + if (decl == lab->label_decl) + break; + + /* If the label is not on named_labels it's a gcc local label, so + it must be in an outer scope, so jumping to it is always OK. */ + if (lab == 0) + return; + + if ((lab->in_try_scope || lab->in_catch_scope || lab->bad_decls) + && !identified) { - pedwarn ("jump to label %q+D", decl); + cp_pedwarn_at ("jump to label `%D'", decl); pedwarn (" from here"); - identified = true; + identified = 1; } - for (bad = ent->bad_decls; bad; bad = TREE_CHAIN (bad)) + for (bad = lab->bad_decls; bad; bad = TREE_CHAIN (bad)) { tree b = TREE_VALUE (bad); int u = decl_jump_unsafe (b); if (u > 1 && DECL_ARTIFICIAL (b)) - { - /* Can't skip init of __exception_info. */ - error ("%J enters catch block", b); - saw_catch = true; - } + /* Can't skip init of __exception_info. */ + error ("%J enters catch block", b); else if (u > 1) - error (" skips initialization of %q+#D", b); + cp_error_at (" skips initialization of `%#D'", b); else - pedwarn (" enters scope of non-POD %q+#D", b); + cp_pedwarn_at (" enters scope of non-POD `%#D'", b); } - if (ent->in_try_scope) + if (lab->in_try_scope) error (" enters try block"); - else if (ent->in_catch_scope && !saw_catch) + else if (lab->in_catch_scope) error (" enters catch block"); - - if (ent->in_omp_scope) - error (" enters OpenMP structured block"); - else if (flag_openmp) - { - struct cp_binding_level *b; - for (b = current_binding_level; b ; b = b->level_chain) - { - if (b == ent->binding_level) - break; - if (b->kind == sk_omp) - { - if (!identified) - { - pedwarn ("jump to label %q+D", decl); - pedwarn (" from here"); - identified = true; - } - error (" exits OpenMP structured block"); - break; - } - } - } -} - -/* Check that a return is ok wrt OpenMP structured blocks. - Called by finish_return_stmt. Returns true if all is well. */ - -bool -check_omp_return (void) -{ - struct cp_binding_level *b; - for (b = current_binding_level; b ; b = b->level_chain) - if (b->kind == sk_omp) - { - error ("invalid exit from OpenMP structured block"); - return false; - } - return true; } /* Define a label, specifying the location in the source file. @@ -2524,22 +2392,19 @@ check_omp_return (void) tree define_label (location_t location, tree name) { - struct named_label_entry *ent, dummy; + tree decl = lookup_label (name); + struct named_label_list *ent; struct cp_binding_level *p; - tree decl; timevar_push (TV_NAME_LOOKUP); - - decl = lookup_label (name); - - dummy.label_decl = decl; - ent = (struct named_label_entry *) htab_find (named_labels, &dummy); - gcc_assert (ent != NULL); + for (ent = named_labels; ent; ent = ent->next) + if (ent->label_decl == decl) + break; /* After labels, make any new cleanups in the function go into their own new (temporary) binding contour. */ - for (p = current_binding_level; - p->kind != sk_function_parms; + for (p = current_binding_level; + p->kind != sk_function_parms; p = p->level_chain) p->more_cleanups_ok = 0; @@ -2547,28 +2412,23 @@ define_label (location_t location, tree name) pedwarn ("label named wchar_t"); if (DECL_INITIAL (decl) != NULL_TREE) - { - error ("duplicate label %qD", decl); - POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); - } + error ("duplicate label `%D'", decl); else { - struct named_label_use_entry *use; - /* Mark label as having been defined. */ DECL_INITIAL (decl) = error_mark_node; /* Say where in the source. */ DECL_SOURCE_LOCATION (decl) = location; - - ent->binding_level = current_binding_level; - ent->names_in_scope = current_binding_level->names; - - for (use = ent->uses; use ; use = use->next) - check_previous_goto (decl, use); - ent->uses = NULL; + if (ent) + { + ent->names_in_scope = current_binding_level->names; + ent->binding_level = current_binding_level; + } + check_previous_gotos (decl); } - POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl); + timevar_pop (TV_NAME_LOOKUP); + return decl; } struct cp_switch @@ -2599,7 +2459,7 @@ static struct cp_switch *switch_stack; void push_switch (tree switch_stmt) { - struct cp_switch *p = XNEW (struct cp_switch); + struct cp_switch *p = xmalloc (sizeof (struct cp_switch)); p->level = current_binding_level; p->next = switch_stack; p->switch_stmt = switch_stmt; @@ -2610,19 +2470,9 @@ push_switch (tree switch_stmt) void pop_switch (void) { - struct cp_switch *cs = switch_stack; - location_t switch_location; - - /* Emit warnings as needed. */ - if (EXPR_HAS_LOCATION (cs->switch_stmt)) - switch_location = EXPR_LOCATION (cs->switch_stmt); - else - switch_location = input_location; - if (!processing_template_decl) - c_do_switch_warnings (cs->cases, switch_location, - SWITCH_STMT_TYPE (cs->switch_stmt), - SWITCH_STMT_COND (cs->switch_stmt)); + struct cp_switch *cs; + cs = switch_stack; splay_tree_delete (cs->cases); switch_stack = switch_stack->next; free (cs); @@ -2648,20 +2498,18 @@ finish_case_label (tree low_value, tree high_value) } /* Find the condition on which this switch statement depends. */ - cond = SWITCH_STMT_COND (switch_stack->switch_stmt); + cond = SWITCH_COND (switch_stack->switch_stmt); if (cond && TREE_CODE (cond) == TREE_LIST) cond = TREE_VALUE (cond); - if (!check_switch_goto (switch_stack->level)) - return error_mark_node; + r = c_add_case_label (switch_stack->cases, cond, low_value, high_value); - r = c_add_case_label (switch_stack->cases, cond, TREE_TYPE (cond), - low_value, high_value); + check_switch_goto (switch_stack->level); /* After labels, make any new cleanups in the function go into their own new (temporary) binding contour. */ - for (p = current_binding_level; - p->kind != sk_function_parms; + for (p = current_binding_level; + p->kind != sk_function_parms; p = p->level_chain) p->more_cleanups_ok = 0; @@ -2682,105 +2530,85 @@ typename_hash (const void* k) return hash; } -typedef struct typename_info { - tree scope; - tree name; - tree template_id; - bool enum_p; - bool class_p; -} typename_info; - /* Compare two TYPENAME_TYPEs. K1 and K2 are really of type `tree'. */ static int typename_compare (const void * k1, const void * k2) { tree t1; - const typename_info *t2; + tree t2; + tree d1; + tree d2; t1 = (tree) k1; - t2 = (const typename_info *) k2; + t2 = (tree) k2; + d1 = TYPE_NAME (t1); + d2 = TYPE_NAME (t2); - return (DECL_NAME (TYPE_NAME (t1)) == t2->name - && TYPE_CONTEXT (t1) == t2->scope - && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id - && TYPENAME_IS_ENUM_P (t1) == t2->enum_p - && TYPENAME_IS_CLASS_P (t1) == t2->class_p); + return (DECL_NAME (d1) == DECL_NAME (d2) + && TYPE_CONTEXT (t1) == TYPE_CONTEXT (t2) + && ((TREE_TYPE (t1) != NULL_TREE) + == (TREE_TYPE (t2) != NULL_TREE)) + && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)) + && TYPENAME_TYPE_FULLNAME (t1) == TYPENAME_TYPE_FULLNAME (t2)); } /* Build a TYPENAME_TYPE. If the type is `typename T::t', CONTEXT is - the type of `T', NAME is the IDENTIFIER_NODE for `t'. + the type of `T', NAME is the IDENTIFIER_NODE for `t'. If BASE_TYPE + is non-NULL, this type is being created by the implicit typename + extension, and BASE_TYPE is a type named `t' in some base class of + `T' which depends on template parameters. Returns the new TYPENAME_TYPE. */ static GTY ((param_is (union tree_node))) htab_t typename_htab; static tree -build_typename_type (tree context, tree name, tree fullname, - enum tag_types tag_type) +build_typename_type (tree context, tree name, tree fullname) { tree t; tree d; - typename_info ti; void **e; - hashval_t hash; if (typename_htab == NULL) - typename_htab = htab_create_ggc (61, &typename_hash, - &typename_compare, NULL); - - ti.scope = FROB_CONTEXT (context); - ti.name = name; - ti.template_id = fullname; - ti.enum_p = tag_type == enum_type; - ti.class_p = (tag_type == class_type - || tag_type == record_type - || tag_type == union_type); - hash = (htab_hash_pointer (ti.scope) - ^ htab_hash_pointer (ti.name)); + { + typename_htab = htab_create_ggc (61, &typename_hash, + &typename_compare, NULL); + } + + /* Build the TYPENAME_TYPE. */ + t = make_aggr_type (TYPENAME_TYPE); + TYPE_CONTEXT (t) = FROB_CONTEXT (context); + TYPENAME_TYPE_FULLNAME (t) = fullname; + + /* Build the corresponding TYPE_DECL. */ + d = build_decl (TYPE_DECL, name, t); + TYPE_NAME (TREE_TYPE (d)) = d; + TYPE_STUB_DECL (TREE_TYPE (d)) = d; + DECL_CONTEXT (d) = FROB_CONTEXT (context); + DECL_ARTIFICIAL (d) = 1; /* See if we already have this type. */ - e = htab_find_slot_with_hash (typename_htab, &ti, hash, INSERT); + e = htab_find_slot (typename_htab, t, INSERT); if (*e) t = (tree) *e; else - { - /* Build the TYPENAME_TYPE. */ - t = make_aggr_type (TYPENAME_TYPE); - TYPE_CONTEXT (t) = ti.scope; - TYPENAME_TYPE_FULLNAME (t) = ti.template_id; - TYPENAME_IS_ENUM_P (t) = ti.enum_p; - TYPENAME_IS_CLASS_P (t) = ti.class_p; - - /* Build the corresponding TYPE_DECL. */ - d = build_decl (TYPE_DECL, name, t); - TYPE_NAME (TREE_TYPE (d)) = d; - TYPE_STUB_DECL (TREE_TYPE (d)) = d; - DECL_CONTEXT (d) = FROB_CONTEXT (context); - DECL_ARTIFICIAL (d) = 1; - - /* Store it in the hash table. */ - *e = t; - } + *e = t; return t; } -/* Resolve `typename CONTEXT::NAME'. TAG_TYPE indicates the tag - provided to name the type. Returns an appropriate type, unless an - error occurs, in which case error_mark_node is returned. If we - locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is set, we - return that, rather than the _TYPE it corresponds to, in other - cases we look through the type decl. If TF_ERROR is set, complain - about errors, otherwise be quiet. */ +/* Resolve `typename CONTEXT::NAME'. Returns an appropriate type, + unless an error occurs, in which case error_mark_node is returned. + If we locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is + set, we return that, rather than the _TYPE it corresponds to, in + other cases we look through the type decl. If TF_ERROR is set, + complain about errors, otherwise be quiet. */ tree -make_typename_type (tree context, tree name, enum tag_types tag_type, - tsubst_flags_t complain) +make_typename_type (tree context, tree name, tsubst_flags_t complain) { tree fullname; - tree t; - bool want_template; if (name == error_mark_node || context == NULL_TREE @@ -2809,88 +2637,92 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, name = TREE_OPERAND (name, 0); if (TREE_CODE (name) == TEMPLATE_DECL) name = TREE_OPERAND (fullname, 0) = DECL_NAME (name); - else if (TREE_CODE (name) == OVERLOAD) - { - error ("%qD is not a type", name); - return error_mark_node; - } } if (TREE_CODE (name) == TEMPLATE_DECL) { - error ("%qD used without template parameters", name); + error ("`%D' used without template parameters", name); return error_mark_node; } - gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); - gcc_assert (TYPE_P (context)); + my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 20030802); + my_friendly_assert (TYPE_P (context), 20050905); - /* When the CONTEXT is a dependent type, NAME could refer to a - dependent base class of CONTEXT. So we cannot peek inside it, - even if CONTEXT is a currently open scope. */ - if (dependent_type_p (context)) - return build_typename_type (context, name, fullname, tag_type); - - if (!IS_AGGR_TYPE (context)) - { - if (complain & tf_error) - error ("%q#T is not a class", context); - return error_mark_node; - } - - want_template = TREE_CODE (fullname) == TEMPLATE_ID_EXPR; - - /* We should only set WANT_TYPE when we're a nested typename type. - Then we can give better diagnostics if we find a non-type. */ - t = lookup_field (context, name, 0, /*want_type=*/true); - if (!t) - { - if (complain & tf_error) - error (want_template ? "no class template named %q#T in %q#T" - : "no type named %q#T in %q#T", name, context); - return error_mark_node; - } - - if (want_template && !DECL_CLASS_TEMPLATE_P (t)) + if (!dependent_type_p (context) + || currently_open_class (context)) { - if (complain & tf_error) - error ("%<typename %T::%D%> names %q#T, which is not a class template", - context, name, t); - return error_mark_node; + if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR) + { + tree tmpl = NULL_TREE; + if (IS_AGGR_TYPE (context)) + tmpl = lookup_field (context, name, 0, false); + if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl)) + { + if (complain & tf_error) + error ("no class template named `%#T' in `%#T'", + name, context); + return error_mark_node; + } + + if (complain & tf_error) + perform_or_defer_access_check (TYPE_BINFO (context), tmpl); + + return lookup_template_class (tmpl, + TREE_OPERAND (fullname, 1), + NULL_TREE, context, + /*entering_scope=*/0, + tf_error | tf_warning | tf_user); + } + else + { + tree t; + + if (!IS_AGGR_TYPE (context)) + { + if (complain & tf_error) + error ("no type named `%#T' in `%#T'", name, context); + return error_mark_node; + } + + t = lookup_field (context, name, 0, true); + if (t) + { + if (TREE_CODE (t) != TYPE_DECL) + { + if (complain & tf_error) + error ("no type named `%#T' in `%#T'", name, context); + return error_mark_node; + } + + if (complain & tf_error) + perform_or_defer_access_check (TYPE_BINFO (context), t); + + if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl)) + t = TREE_TYPE (t); + + return t; + } + } } - if (!want_template && TREE_CODE (t) != TYPE_DECL) + + /* If the CONTEXT is not a template type, then either the field is + there now or its never going to be. */ + if (!dependent_type_p (context)) { if (complain & tf_error) - error ("%<typename %T::%D%> names %q#T, which is not a type", - context, name, t); + error ("no type named `%#T' in `%#T'", name, context); return error_mark_node; } - - if (complain & tf_error) - perform_or_defer_access_check (TYPE_BINFO (context), t, t); - - if (want_template) - return lookup_template_class (t, TREE_OPERAND (fullname, 1), - NULL_TREE, context, - /*entering_scope=*/0, - tf_warning_or_error | tf_user); - - if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl)) - t = TREE_TYPE (t); - - return t; -} -/* Resolve `CONTEXT::template NAME'. Returns a TEMPLATE_DECL if the name - can be resolved or an UNBOUND_CLASS_TEMPLATE, unless an error occurs, - in which case error_mark_node is returned. - - If PARM_LIST is non-NULL, also make sure that the template parameter - list of TEMPLATE_DECL matches. + return build_typename_type (context, name, fullname); +} - If COMPLAIN zero, don't complain about any errors that occur. */ +/* Resolve `CONTEXT::template NAME'. Returns an appropriate type, + unless an error occurs, in which case error_mark_node is returned. + If we locate a TYPE_DECL, we return that, rather than the _TYPE it + corresponds to. If COMPLAIN zero, don't complain about any errors + that occur. */ tree -make_unbound_class_template (tree context, tree name, tree parm_list, - tsubst_flags_t complain) +make_unbound_class_template (tree context, tree name, tsubst_flags_t complain) { tree t; tree d; @@ -2899,7 +2731,8 @@ make_unbound_class_template (tree context, tree name, tree parm_list, name = TYPE_IDENTIFIER (name); else if (DECL_P (name)) name = DECL_NAME (name); - gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); + if (TREE_CODE (name) != IDENTIFIER_NODE) + abort (); if (!dependent_type_p (context) || currently_open_class (context)) @@ -2912,23 +2745,12 @@ make_unbound_class_template (tree context, tree name, tree parm_list, if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl)) { if (complain & tf_error) - error ("no class template named %q#T in %q#T", name, context); - return error_mark_node; - } - - if (parm_list - && !comp_template_parms (DECL_TEMPLATE_PARMS (tmpl), parm_list)) - { - if (complain & tf_error) - { - error ("template parameters do not match template"); - error ("%q+D declared here", tmpl); - } + error ("no class template named `%#T' in `%#T'", name, context); return error_mark_node; } - + if (complain & tf_error) - perform_or_defer_access_check (TYPE_BINFO (context), tmpl, tmpl); + perform_or_defer_access_check (TYPE_BINFO (context), tmpl); return tmpl; } @@ -2944,22 +2766,33 @@ make_unbound_class_template (tree context, tree name, tree parm_list, TYPE_STUB_DECL (TREE_TYPE (d)) = d; DECL_CONTEXT (d) = FROB_CONTEXT (context); DECL_ARTIFICIAL (d) = 1; - DECL_TEMPLATE_PARMS (d) = parm_list; return t; } +/* A chain of TYPE_DECLs for the builtin types. */ + +static GTY(()) tree builtin_type_decls; + +/* Return a chain of TYPE_DECLs for the builtin types. */ + +tree +cxx_builtin_type_decls (void) +{ + return builtin_type_decls; +} + /* Push the declarations of builtin types into the namespace. RID_INDEX is the index of the builtin type in the array RID_POINTERS. NAME is the name used when looking up the builtin type. TYPE is the _TYPE node for the builtin type. */ void -record_builtin_type (enum rid rid_index, - const char* name, - tree type) +record_builtin_type (enum rid rid_index, + const char* name, + tree type) { tree rname = NULL_TREE, tname = NULL_TREE; tree tdecl = NULL_TREE; @@ -2994,7 +2827,10 @@ record_builtin_type (enum rid rid_index, TYPE_NAME (type) = tdecl; if (tdecl) - debug_hooks->type_decl (tdecl, 0); + { + TREE_CHAIN (tdecl) = builtin_type_decls; + builtin_type_decls = tdecl; + } } /* Record one of the standard Java types. @@ -3046,7 +2882,7 @@ record_unknown_type (tree type, const char* name) TYPE_MODE (type) = TYPE_MODE (void_type_node); } -/* A string for which we should create an IDENTIFIER_NODE at +/* An string for which we should create an IDENTIFIER_NODE at startup. */ typedef struct predefined_identifier @@ -3071,15 +2907,13 @@ initialize_predefined_identifiers (void) { "C++", &lang_name_cplusplus, 0 }, { "C", &lang_name_c, 0 }, { "Java", &lang_name_java, 0 }, - /* Some of these names have a trailing space so that it is - impossible for them to conflict with names written by users. */ - { "__ct ", &ctor_identifier, 1 }, - { "__base_ctor ", &base_ctor_identifier, 1 }, - { "__comp_ctor ", &complete_ctor_identifier, 1 }, - { "__dt ", &dtor_identifier, 1 }, - { "__comp_dtor ", &complete_dtor_identifier, 1 }, - { "__base_dtor ", &base_dtor_identifier, 1 }, - { "__deleting_dtor ", &deleting_dtor_identifier, 1 }, + { CTOR_NAME, &ctor_identifier, 1 }, + { "__base_ctor", &base_ctor_identifier, 1 }, + { "__comp_ctor", &complete_ctor_identifier, 1 }, + { DTOR_NAME, &dtor_identifier, 1 }, + { "__comp_dtor", &complete_dtor_identifier, 1 }, + { "__base_dtor", &base_dtor_identifier, 1 }, + { "__deleting_dtor", &deleting_dtor_identifier, 1 }, { IN_CHARGE_NAME, &in_charge_identifier, 0 }, { "nelts", &nelts_identifier, 0 }, { THIS_NAME, &this_identifier, 0 }, @@ -3111,21 +2945,21 @@ cxx_init_decl_processing (void) tree void_ftype; tree void_ftype_ptr; - build_common_tree_nodes (flag_signed_char, false); - /* Create all the identifiers we need. */ initialize_predefined_identifiers (); + /* Fill in back-end hooks. */ + lang_missing_noreturn_ok_p = &cp_missing_noreturn_ok_p; + /* Create the global variables. */ push_to_top_level (); current_function_decl = NULL_TREE; current_binding_level = NULL; /* Enter the global namespace. */ - gcc_assert (global_namespace == NULL_TREE); + my_friendly_assert (global_namespace == NULL_TREE, 375); global_namespace = build_lang_decl (NAMESPACE_DECL, global_scope_name, - void_type_node); - TREE_PUBLIC (global_namespace) = 1; + void_type_node); begin_scope (sk_namespace, global_namespace); current_lang_name = NULL_TREE; @@ -3139,7 +2973,10 @@ cxx_init_decl_processing (void) flag_no_inline = 1; } if (flag_inline_functions) - flag_inline_trees = 2; + { + flag_inline_trees = 2; + flag_inline_functions = 0; + } /* Force minimum function alignment if using the least significant bit of function pointers to store the virtual bit. */ @@ -3150,6 +2987,11 @@ cxx_init_decl_processing (void) /* Initially, C. */ current_lang_name = lang_name_c; + build_common_tree_nodes (flag_signed_char); + + error_mark_list = build_tree_list (error_mark_node, error_mark_node); + TREE_TYPE (error_mark_list) = error_mark_node; + /* Create the `std' namespace. */ push_namespace (std_identifier); std_node = current_namespace; @@ -3166,8 +3008,10 @@ cxx_init_decl_processing (void) java_char_type_node = record_builtin_java_type ("__java_char", -16); java_boolean_type_node = record_builtin_java_type ("__java_boolean", -1); - integer_two_node = build_int_cst (NULL_TREE, 2); - integer_three_node = build_int_cst (NULL_TREE, 3); + integer_two_node = build_int_2 (2, 0); + TREE_TYPE (integer_two_node) = integer_type_node; + integer_three_node = build_int_2 (3, 0); + TREE_TYPE (integer_three_node) = integer_type_node; record_builtin_type (RID_BOOL, "bool", boolean_type_node); truthvalue_type_node = boolean_type_node; @@ -3187,7 +3031,7 @@ cxx_init_decl_processing (void) void_ftype = build_function_type (void_type_node, void_list_node); void_ftype_ptr = build_function_type (void_type_node, tree_cons (NULL_TREE, - ptr_type_node, + ptr_type_node, void_list_node)); void_ftype_ptr = build_exception_variant (void_ftype_ptr, empty_except_spec); @@ -3247,13 +3091,13 @@ cxx_init_decl_processing (void) bad_alloc_id = get_identifier ("bad_alloc"); bad_alloc_type_node = make_aggr_type (RECORD_TYPE); TYPE_CONTEXT (bad_alloc_type_node) = current_namespace; - bad_alloc_decl + bad_alloc_decl = create_implicit_typedef (bad_alloc_id, bad_alloc_type_node); DECL_CONTEXT (bad_alloc_decl) = current_namespace; TYPE_STUB_DECL (bad_alloc_type_node) = bad_alloc_decl; pop_namespace (); - - ptr_ftype_sizetype + + ptr_ftype_sizetype = build_function_type (ptr_type_node, tree_cons (NULL_TREE, size_type_node, @@ -3273,6 +3117,7 @@ cxx_init_decl_processing (void) /* Perform other language dependent initializations. */ init_class_processing (); + init_search_processing (); init_rtti_processing (); if (flag_exceptions) @@ -3285,8 +3130,12 @@ cxx_init_decl_processing (void) start_fname_decls (); /* Show we use EH for cleanups. */ - if (flag_exceptions) - using_eh_for_cleanups (); + using_eh_for_cleanups (); + + /* Maintain consistency. Perhaps we should just complain if they + say -fwritable-strings? */ + if (flag_writable_strings) + flag_const_strings = 0; } /* Generate an initializer for a function naming variable from @@ -3307,17 +3156,17 @@ cp_fname_init (const char* name, tree *type_p) domain = build_index_type (size_int (length)); init = build_string (length + 1, name); } - + type = build_qualified_type (char_type_node, TYPE_QUAL_CONST); type = build_cplus_array_type (type, domain); *type_p = type; - + if (init) TREE_TYPE (init) = type; else init = error_mark_node; - + return init; } @@ -3325,7 +3174,7 @@ cp_fname_init (const char* name, tree *type_p) decl, NAME is the initialization string and TYPE_DEP indicates whether NAME depended on the type of the function. We make use of that to detect __PRETTY_FUNCTION__ inside a template fn. This is being done - lazily at the point of first use, so we mustn't push the decl now. */ + lazily at the point of first use, so we musn't push the decl now. */ static tree cp_make_fname_decl (tree id, int type_dep) @@ -3336,17 +3185,15 @@ cp_make_fname_decl (tree id, int type_dep) tree init = cp_fname_init (name, &type); tree decl = build_decl (VAR_DECL, id, type); - if (name) - free ((char *) name); - /* As we're using pushdecl_with_scope, we must set the context. */ DECL_CONTEXT (decl) = current_function_decl; DECL_PRETTY_FUNCTION_P (decl) = type_dep; - + TREE_STATIC (decl) = 1; TREE_READONLY (decl) = 1; DECL_ARTIFICIAL (decl) = 1; - + DECL_INITIAL (decl) = init; + TREE_USED (decl) = 1; if (current_function_decl) @@ -3354,13 +3201,12 @@ cp_make_fname_decl (tree id, int type_dep) struct cp_binding_level *b = current_binding_level; while (b->level_chain->kind != sk_function_parms) b = b->level_chain; - pushdecl_with_scope (decl, b, /*is_friend=*/false); - cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); + pushdecl_with_scope (decl, b); + cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING); } else pushdecl_top_level_and_finish (decl, init); - + return decl; } @@ -3378,12 +3224,12 @@ cp_make_fname_decl (tree id, int type_dep) static tree builtin_function_1 (const char* name, - tree type, - tree context, - enum built_in_function code, - enum built_in_class class, - const char* libname, - tree attrs) + tree type, + tree context, + int code, + enum built_in_class class, + const char* libname, + tree attrs) { tree decl = build_library_fn_1 (get_identifier (name), ERROR_MARK, type); DECL_BUILT_IN_CLASS (decl) = class; @@ -3397,10 +3243,10 @@ builtin_function_1 (const char* name, function in the namespace. */ if (libname) SET_DECL_ASSEMBLER_NAME (decl, get_identifier (libname)); + make_decl_rtl (decl, NULL); - /* A function in the user's namespace should have an explicit - declaration before it is used. Mark the built-in function as - anticipated but not actually declared. */ + /* Warn if a function in the namespace for users + is used without an occasion to consider it declared. */ if (name[0] != '_' || name[1] != '_') DECL_ANTICIPATED (decl) = 1; @@ -3431,23 +3277,23 @@ builtin_function_1 (const char* name, tree builtin_function (const char* name, - tree type, - int code, - enum built_in_class cl, - const char* libname, - tree attrs) + tree type, + int code, + enum built_in_class class, + const char* libname, + tree attrs) { /* All builtins that don't begin with an '_' should additionally go in the 'std' namespace. */ if (name[0] != '_') { push_namespace (std_identifier); - builtin_function_1 (name, type, std_node, code, cl, libname, attrs); + builtin_function_1 (name, type, std_node, code, class, libname, attrs); pop_namespace (); } return builtin_function_1 (name, type, NULL_TREE, code, - cl, libname, attrs); + class, libname, attrs); } /* Generate a FUNCTION_DECL with the typical flags for a runtime library @@ -3460,12 +3306,9 @@ build_library_fn_1 (tree name, enum tree_code operator_code, tree type) DECL_EXTERNAL (fn) = 1; TREE_PUBLIC (fn) = 1; DECL_ARTIFICIAL (fn) = 1; + TREE_NOTHROW (fn) = 1; SET_OVERLOADED_OPERATOR_CODE (fn, operator_code); SET_DECL_LANGUAGE (fn, lang_c); - /* Runtime library routines are, by definition, available in an - external shared object. */ - DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT; - DECL_VISIBILITY_SPECIFIED (fn) = 1; return fn; } @@ -3476,9 +3319,7 @@ build_library_fn_1 (tree name, enum tree_code operator_code, tree type) tree build_library_fn (tree name, tree type) { - tree fn = build_library_fn_1 (name, ERROR_MARK, type); - TREE_NOTHROW (fn) = 1; - return fn; + return build_library_fn_1 (name, ERROR_MARK, type); } /* Returns the _DECL for a library function with C++ linkage. */ @@ -3490,6 +3331,7 @@ build_cp_library_fn (tree name, enum tree_code operator_code, tree type) TREE_NOTHROW (fn) = TYPE_NOTHROW_P (type); DECL_CONTEXT (fn) = FROB_CONTEXT (current_namespace); SET_DECL_LANGUAGE (fn, lang_cplusplus); + set_mangled_name_for_decl (fn); return fn; } @@ -3610,15 +3452,15 @@ fixup_anonymous_aggr (tree t) type = TREE_TYPE (field); if (CLASS_TYPE_P (type)) { - if (TYPE_NEEDS_CONSTRUCTING (type)) - error ("member %q+#D with constructor not allowed " - "in anonymous aggregate", field); + if (TYPE_NEEDS_CONSTRUCTING (type)) + cp_error_at ("member %#D' with constructor not allowed in anonymous aggregate", + field); if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) - error ("member %q+#D with destructor not allowed " - "in anonymous aggregate", field); + cp_error_at ("member %#D' with destructor not allowed in anonymous aggregate", + field); if (TYPE_HAS_COMPLEX_ASSIGN_REF (type)) - error ("member %q+#D with copy assignment operator " - "not allowed in anonymous aggregate", field); + cp_error_at ("member %#D' with copy assignment operator not allowed in anonymous aggregate", + field); } } } @@ -3630,10 +3472,13 @@ fixup_anonymous_aggr (tree t) Returns the type declared; or NULL_TREE if none. */ tree -check_tag_decl (cp_decl_specifier_seq *declspecs) +check_tag_decl (tree declspecs) { - int saw_friend = declspecs->specs[(int)ds_friend] != 0; - int saw_typedef = declspecs->specs[(int)ds_typedef] != 0; + int found_type = 0; + int saw_friend = 0; + int saw_typedef = 0; + tree ob_modifier = NULL_TREE; + tree link; /* If a class, struct, or enum type is declared by the DECLSPECS (i.e, if a class-specifier, enum-specifier, or non-typename elaborated-type-specifier appears in the DECLSPECS), @@ -3641,24 +3486,59 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) tree declared_type = NULL_TREE; bool error_p = false; - if (declspecs->multiple_types_p) - error ("multiple types in one declaration"); - else if (declspecs->redefined_builtin_type) + for (link = declspecs; link; link = TREE_CHAIN (link)) { - if (!in_system_header) - pedwarn ("redeclaration of C++ built-in type %qT", - declspecs->redefined_builtin_type); - return NULL_TREE; - } + tree value = TREE_VALUE (link); + + if (TYPE_P (value) || TREE_CODE (value) == TYPE_DECL + || (TREE_CODE (value) == IDENTIFIER_NODE + && is_typename_at_global_scope (value))) + { + ++found_type; + + if (found_type == 2 && TREE_CODE (value) == IDENTIFIER_NODE) + { + if (! in_system_header) + pedwarn ("redeclaration of C++ built-in type `%T'", value); + return NULL_TREE; + } + + if (TYPE_P (value) + && ((TREE_CODE (value) != TYPENAME_TYPE && IS_AGGR_TYPE (value)) + || TREE_CODE (value) == ENUMERAL_TYPE)) + { + my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261); + declared_type = value; + } + } + else if (value == ridpointers[(int) RID_TYPEDEF]) + saw_typedef = 1; + else if (value == ridpointers[(int) RID_FRIEND]) + { + if (current_class_type == NULL_TREE + || current_scope () != current_class_type) + ob_modifier = value; + else + saw_friend = 1; + } + else if (value == ridpointers[(int) RID_STATIC] + || value == ridpointers[(int) RID_EXTERN] + || value == ridpointers[(int) RID_AUTO] + || value == ridpointers[(int) RID_REGISTER] + || value == ridpointers[(int) RID_INLINE] + || value == ridpointers[(int) RID_VIRTUAL] + || value == ridpointers[(int) RID_CONST] + || value == ridpointers[(int) RID_VOLATILE] + || value == ridpointers[(int) RID_EXPLICIT] + || value == ridpointers[(int) RID_THREAD]) + ob_modifier = value; + else if (value == error_mark_node) + error_p = true; + } + + if (found_type > 1) + error ("multiple types in one declaration"); - if (declspecs->type - && TYPE_P (declspecs->type) - && ((TREE_CODE (declspecs->type) != TYPENAME_TYPE - && IS_AGGR_TYPE (declspecs->type)) - || TREE_CODE (declspecs->type) == ENUMERAL_TYPE)) - declared_type = declspecs->type; - else if (declspecs->type == error_mark_node) - error_p = true; if (declared_type == NULL_TREE && ! saw_friend && !error_p) pedwarn ("declaration does not declare anything"); /* Check for an anonymous union. */ @@ -3666,56 +3546,47 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) && TYPE_ANONYMOUS_P (declared_type)) { /* 7/3 In a simple-declaration, the optional init-declarator-list - can be omitted only when declaring a class (clause 9) or - enumeration (7.2), that is, when the decl-specifier-seq contains - either a class-specifier, an elaborated-type-specifier with - a class-key (9.1), or an enum-specifier. In these cases and - whenever a class-specifier or enum-specifier is present in the - decl-specifier-seq, the identifiers in these specifiers are among - the names being declared by the declaration (as class-name, - enum-names, or enumerators, depending on the syntax). In such - cases, and except for the declaration of an unnamed bit-field (9.6), - the decl-specifier-seq shall introduce one or more names into the - program, or shall redeclare a name introduced by a previous - declaration. [Example: - enum { }; // ill-formed - typedef class { }; // ill-formed - --end example] */ + can be omitted only when declaring a class (clause 9) or + enumeration (7.2), that is, when the decl-specifier-seq contains + either a class-specifier, an elaborated-type-specifier with + a class-key (9.1), or an enum-specifier. In these cases and + whenever a class-specifier or enum-specifier is present in the + decl-specifier-seq, the identifiers in these specifiers are among + the names being declared by the declaration (as class-name, + enum-names, or enumerators, depending on the syntax). In such + cases, and except for the declaration of an unnamed bit-field (9.6), + the decl-specifier-seq shall introduce one or more names into the + program, or shall redeclare a name introduced by a previous + declaration. [Example: + enum { }; // ill-formed + typedef class { }; // ill-formed + --end example] */ if (saw_typedef) - { - error ("missing type-name in typedef-declaration"); - return NULL_TREE; - } + { + error ("missing type-name in typedef-declaration"); + return NULL_TREE; + } /* Anonymous unions are objects, so they can have specifiers. */; SET_ANON_AGGR_TYPE_P (declared_type); - if (TREE_CODE (declared_type) != UNION_TYPE && pedantic + if (TREE_CODE (declared_type) != UNION_TYPE && pedantic && !in_system_header) pedwarn ("ISO C++ prohibits anonymous structs"); } - else + else if (ob_modifier) { - if (declspecs->specs[(int)ds_inline] - || declspecs->specs[(int)ds_virtual]) - error ("%qs can only be specified for functions", - declspecs->specs[(int)ds_inline] - ? "inline" : "virtual"); - else if (saw_friend - && (!current_class_type - || current_scope () != current_class_type)) - error ("%<friend%> can only be specified inside a class"); - else if (declspecs->specs[(int)ds_explicit]) - error ("%<explicit%> can only be specified for constructors"); - else if (declspecs->storage_class) - error ("a storage class can only be specified for objects " - "and functions"); - else if (declspecs->specs[(int)ds_const] - || declspecs->specs[(int)ds_volatile] - || declspecs->specs[(int)ds_restrict] - || declspecs->specs[(int)ds_thread]) - error ("qualifiers can only be specified for objects " - "and functions"); + if (ob_modifier == ridpointers[(int) RID_INLINE] + || ob_modifier == ridpointers[(int) RID_VIRTUAL]) + error ("`%D' can only be specified for functions", ob_modifier); + else if (ob_modifier == ridpointers[(int) RID_FRIEND]) + error ("`%D' can only be specified inside a class", ob_modifier); + else if (ob_modifier == ridpointers[(int) RID_EXPLICIT]) + error ("`%D' can only be specified for constructors", + ob_modifier); + else + error ("`%D' can only be specified for objects and functions", + ob_modifier); } return declared_type; @@ -3730,28 +3601,19 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) Otherwise, it is an error. C++: may have to grok the declspecs to learn about static, - complain for anonymous unions. + complain for anonymous unions. Returns the TYPE declared -- or NULL_TREE if none. */ tree -shadow_tag (cp_decl_specifier_seq *declspecs) +shadow_tag (tree declspecs) { tree t = check_tag_decl (declspecs); if (!t) return NULL_TREE; - if (declspecs->attributes) - { - warning (0, "attribute ignored in declaration of %q+#T", t); - warning (0, "attribute for %q+#T must follow the %qs keyword", - t, class_key_or_enum_as_string (t)); - - } - - if (maybe_process_partial_specialization (t) == error_mark_node) - return NULL_TREE; + maybe_process_partial_specialization (t); /* This is where the variables in an anonymous union are declared. An anonymous union declaration looks like: @@ -3764,8 +3626,8 @@ shadow_tag (cp_decl_specifier_seq *declspecs) if (TYPE_FIELDS (t)) { - tree decl = grokdeclarator (/*declarator=*/NULL, - declspecs, NORMAL, 0, NULL); + tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0, + NULL); finish_anon_union (decl); } } @@ -3776,14 +3638,15 @@ shadow_tag (cp_decl_specifier_seq *declspecs) /* Decode a "typename", such as "int **", returning a ..._TYPE node. */ tree -groktypename (cp_decl_specifier_seq *type_specifiers, - const cp_declarator *declarator) +groktypename (tree typename) { - tree attrs; + tree specs, attrs; tree type; - attrs = type_specifiers->attributes; - type_specifiers->attributes = NULL_TREE; - type = grokdeclarator (declarator, type_specifiers, TYPENAME, 0, &attrs); + if (TREE_CODE (typename) != TREE_LIST) + return typename; + split_specs_attrs (TREE_PURPOSE (typename), &specs, &attrs); + type = grokdeclarator (TREE_VALUE (typename), specs, + TYPENAME, 0, &attrs); if (attrs) cplus_decl_attributes (&type, attrs, 0); return type; @@ -3805,19 +3668,23 @@ groktypename (cp_decl_specifier_seq *type_specifiers, grokfield and not through here. */ tree -start_decl (const cp_declarator *declarator, - cp_decl_specifier_seq *declspecs, - int initialized, - tree attributes, - tree prefix_attributes, - tree *pushed_scope_p) +start_decl (tree declarator, + tree declspecs, + int initialized, + tree attributes, + tree prefix_attributes) { tree decl; tree type, tem; tree context; - bool was_public; - *pushed_scope_p = NULL_TREE; + /* This should only be done once on the top most decl. */ + if (have_extern_spec) + { + declspecs = tree_cons (NULL_TREE, get_identifier ("extern"), + declspecs); + have_extern_spec = false; + } /* An object declared as __attribute__((deprecated)) suppresses warnings of uses of other deprecated items. */ @@ -3831,23 +3698,28 @@ start_decl (const cp_declarator *declarator, deprecated_state = DEPRECATED_NORMAL; - if (decl == NULL_TREE || TREE_CODE (decl) == VOID_TYPE - || decl == error_mark_node) + if (decl == NULL_TREE || TREE_CODE (decl) == VOID_TYPE) return error_mark_node; type = TREE_TYPE (decl); + if (type == error_mark_node) + return error_mark_node; + context = DECL_CONTEXT (decl); - if (context) + if (initialized && context && TREE_CODE (context) == NAMESPACE_DECL + && context != current_namespace && TREE_CODE (decl) == VAR_DECL) { - *pushed_scope_p = push_scope (context); - - /* We are only interested in class contexts, later. */ - if (TREE_CODE (context) == NAMESPACE_DECL) - context = NULL_TREE; + /* When parsing the initializer, lookup should use the object's + namespace. */ + push_decl_namespace (context); } + /* We are only interested in class contexts, later. */ + if (context && TREE_CODE (context) == NAMESPACE_DECL) + context = NULL_TREE; + if (initialized) /* Is it valid for this decl to have an initializer at all? If not, set INITIALIZED to zero, which will indirectly @@ -3855,12 +3727,14 @@ start_decl (const cp_declarator *declarator, switch (TREE_CODE (decl)) { case TYPE_DECL: - error ("typedef %qD is initialized (use __typeof__ instead)", decl); - return error_mark_node; + error ("typedef `%D' is initialized (use __typeof__ instead)", decl); + initialized = 0; + break; case FUNCTION_DECL: - error ("function %q#D is initialized like a variable", decl); - return error_mark_node; + error ("function `%#D' is initialized like a variable", decl); + initialized = 0; + break; default: break; @@ -3870,108 +3744,91 @@ start_decl (const cp_declarator *declarator, { if (! toplevel_bindings_p () && DECL_EXTERNAL (decl)) - warning (0, "declaration of %q#D has %<extern%> and is initialized", - decl); + warning ("declaration of `%#D' has `extern' and is initialized", + decl); DECL_EXTERNAL (decl) = 0; if (toplevel_bindings_p ()) TREE_STATIC (decl) = 1; + + /* Tell `pushdecl' this is an initialized decl + even though we don't yet have the initializer expression. + Also tell `cp_finish_decl' it may store the real initializer. */ + DECL_INITIAL (decl) = error_mark_node; } /* Set attributes here so if duplicate decl, will have proper attributes. */ cplus_decl_attributes (&decl, attributes, 0); - /* Dllimported symbols cannot be defined. Static data members (which - can be initialized in-class and dllimported) go through grokfield, - not here, so we don't need to exclude those decls when checking for - a definition. */ - if (initialized && DECL_DLLIMPORT_P (decl)) - { - error ("definition of %q#D is marked %<dllimport%>", decl); - DECL_DLLIMPORT_P (decl) = 0; - } - /* If #pragma weak was used, mark the decl weak now. */ - maybe_apply_pragma_weak (decl); + if (global_scope_p (current_binding_level)) + maybe_apply_pragma_weak (decl); if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl) && DECL_UNINLINABLE (decl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl))) - warning (0, "inline function %q+D given attribute noinline", decl); + warning ("%Jinline function '%D' given attribute noinline", decl, decl); if (context && COMPLETE_TYPE_P (complete_type (context))) { + push_nested_class (context); + if (TREE_CODE (decl) == VAR_DECL) { tree field = lookup_field (context, DECL_NAME (decl), 0, false); if (field == NULL_TREE || TREE_CODE (field) != VAR_DECL) - error ("%q#D is not a static member of %q#T", decl, context); + error ("`%#D' is not a static member of `%#T'", decl, context); else { if (DECL_CONTEXT (field) != context) { if (!same_type_p (DECL_CONTEXT (field), context)) - pedwarn ("ISO C++ does not permit %<%T::%D%> " - "to be defined as %<%T::%D%>", + pedwarn ("ISO C++ does not permit `%T::%D' to be defined as `%T::%D'", DECL_CONTEXT (field), DECL_NAME (decl), context, DECL_NAME (decl)); DECL_CONTEXT (decl) = DECL_CONTEXT (field); } - if (processing_specialization - && template_class_depth (context) == 0 - && CLASSTYPE_TEMPLATE_SPECIALIZATION (context)) - error ("template header not allowed in member definition " - "of explicitly specialized class"); /* Static data member are tricky; an in-class initialization still doesn't provide a definition, so the in-class declaration will have DECL_EXTERNAL set, but will have an initialization. Thus, duplicate_decls won't warn about this situation, and so we check here. */ - if (initialized && DECL_INITIALIZED_IN_CLASS_P (field)) - error ("duplicate initialization of %qD", decl); - if (duplicate_decls (decl, field, /*newdecl_is_friend=*/false)) + if (DECL_INITIAL (decl) && DECL_INITIAL (field)) + error ("duplicate initialization of %D", decl); + if (duplicate_decls (decl, field)) decl = field; } } else { tree field = check_classfn (context, decl, - (processing_template_decl - > template_class_depth (context)) - ? current_template_parms - : NULL_TREE); - if (field && duplicate_decls (decl, field, - /*newdecl_is_friend=*/false)) + processing_template_decl + > template_class_depth (context)); + if (field && duplicate_decls (decl, field)) decl = field; } /* cp_finish_decl sets DECL_EXTERNAL if DECL_IN_AGGR_P is set. */ DECL_IN_AGGR_P (decl) = 0; - /* Do not mark DECL as an explicit specialization if it was not - already marked as an instantiation; a declaration should - never be marked as a specialization unless we know what - template is being specialized. */ - if (DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl)) + if ((DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl)) + || CLASSTYPE_TEMPLATE_INSTANTIATION (context)) { SET_DECL_TEMPLATE_SPECIALIZATION (decl); - /* [temp.expl.spec] An explicit specialization of a static data member of a template is a definition if the declaration includes an initializer; otherwise, it is a declaration. We check for processing_specialization so this only applies to the new specialization syntax. */ - if (!initialized && processing_specialization) + if (DECL_INITIAL (decl) == NULL_TREE && processing_specialization) DECL_EXTERNAL (decl) = 1; } if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)) - pedwarn ("declaration of %q#D outside of class is not definition", - decl); + pedwarn ("declaration of `%#D' outside of class is not definition", + decl); } - was_public = TREE_PUBLIC (decl); - /* Enter this declaration into the symbol table. */ tem = maybe_push_decl (decl); @@ -3980,48 +3837,32 @@ start_decl (const cp_declarator *declarator, if (tem == error_mark_node) return error_mark_node; +#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS) /* Tell the back-end to use or not use .common as appropriate. If we say -fconserve-space, we want this to save .data space, at the expense of wrong semantics. If we say -fno-conserve-space, we want this to produce errors about redefs; to do this we force variables into the data segment. */ - if (flag_conserve_space - && TREE_CODE (tem) == VAR_DECL - && TREE_PUBLIC (tem) - && !DECL_THREAD_LOCAL_P (tem) - && !have_global_bss_p ()) - DECL_COMMON (tem) = 1; - - if (TREE_CODE (tem) == VAR_DECL - && DECL_NAMESPACE_SCOPE_P (tem) && !TREE_PUBLIC (tem) && !was_public - && !DECL_THIS_STATIC (tem) && !DECL_ARTIFICIAL (tem)) - { - /* This is a const variable with implicit 'static'. Set - DECL_THIS_STATIC so we can tell it from variables that are - !TREE_PUBLIC because of the anonymous namespace. */ - gcc_assert (cp_type_readonly (TREE_TYPE (tem))); - DECL_THIS_STATIC (tem) = 1; - } + DECL_COMMON (tem) = ((TREE_CODE (tem) != VAR_DECL + || !DECL_THREAD_LOCAL (tem)) + && (flag_conserve_space || ! TREE_PUBLIC (tem))); +#endif - if (!processing_template_decl && TREE_CODE (tem) == VAR_DECL) - start_decl_1 (tem, initialized); + if (! processing_template_decl) + start_decl_1 (tem); return tem; } void -start_decl_1 (tree decl, bool initialized) +start_decl_1 (tree decl) { - tree type; - - gcc_assert (!processing_template_decl); + tree type = TREE_TYPE (decl); + int initialized = (DECL_INITIAL (decl) != NULL_TREE); - if (error_operand_p (decl)) + if (type == error_mark_node) return; - gcc_assert (TREE_CODE (decl) == VAR_DECL); - type = TREE_TYPE (decl); - if (initialized) /* Is it valid for this decl to have an initializer at all? If not, set INITIALIZED to zero, which will indirectly @@ -4033,24 +3874,31 @@ start_decl_1 (tree decl, bool initialized) ; /* A complete type is ok. */ else if (TREE_CODE (type) != ARRAY_TYPE) { - error ("variable %q#D has initializer but incomplete type", decl); + error ("variable `%#D' has initializer but incomplete type", + decl); initialized = 0; type = TREE_TYPE (decl) = error_mark_node; } else if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (type)))) { if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)) - error ("elements of array %q#D have incomplete type", decl); + error ("elements of array `%#D' have incomplete type", decl); /* else we already gave an error in start_decl. */ initialized = 0; } } - else if (IS_AGGR_TYPE (type) - && ! DECL_EXTERNAL (decl)) + + if (!initialized + && TREE_CODE (decl) != TYPE_DECL + && TREE_CODE (decl) != TEMPLATE_DECL + && type != error_mark_node + && IS_AGGR_TYPE (type) + && ! DECL_EXTERNAL (decl)) { - if (!COMPLETE_TYPE_P (complete_type (type))) + if ((! processing_template_decl || ! uses_template_parms (type)) + && !COMPLETE_TYPE_P (complete_type (type))) { - error ("aggregate %q#D has incomplete type and cannot be defined", + error ("aggregate `%#D' has incomplete type and cannot be defined", decl); /* Change the type so that assemble_variable will give DECL an rtl we can live with: (mem (const_int 0)). */ @@ -4068,6 +3916,9 @@ start_decl_1 (tree decl, bool initialized) } } + if (! initialized) + DECL_INITIAL (decl) = NULL_TREE; + /* Create a new scope to hold this declaration if necessary. Whether or not a new scope is necessary cannot be determined until after the type has been completed; if the type is a @@ -4097,20 +3948,22 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup) if ((DECL_LANG_SPECIFIC (decl) == 0 || DECL_IN_AGGR_P (decl) == 0) && ! DECL_THIS_EXTERN (decl)) - error ("%qD declared as reference but not initialized", decl); + error ("`%D' declared as reference but not initialized", decl); return NULL_TREE; } if (TREE_CODE (init) == CONSTRUCTOR) { - error ("ISO C++ forbids use of initializer list to " - "initialize reference %qD", decl); + error ("ISO C++ forbids use of initializer list to initialize reference `%D'", decl); return NULL_TREE; } if (TREE_CODE (init) == TREE_LIST) init = build_x_compound_expr_from_list (init, "initializer"); + if (TREE_CODE (TREE_TYPE (init)) == REFERENCE_TYPE) + init = convert_from_reference (init); + if (TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE) /* Note: default conversion is only called in very special cases. */ @@ -4118,8 +3971,8 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup) /* Convert INIT to the reference type TYPE. This may involve the creation of a temporary, whose lifetime must be the same as that - of the reference. If so, a DECL_EXPR for the temporary will be - added just after the DECL_EXPR for DECL. That's why we don't set + of the reference. If so, a DECL_STMT for the temporary will be + added just after the DECL_STMT for DECL. That's why we don't set DECL_INITIAL for local references (instead assigning to them explicitly); we need to allow the temporary to be initialized first. */ @@ -4129,7 +3982,7 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup) return NULL_TREE; else if (tmp == NULL_TREE) { - error ("cannot initialize %qT from %qT", type, TREE_TYPE (init)); + error ("cannot initialize `%T' from `%T'", type, TREE_TYPE (init)); return NULL_TREE; } @@ -4141,30 +3994,6 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup) return NULL_TREE; } -/* Designated initializers in arrays are not supported in GNU C++. - The parser cannot detect this error since it does not know whether - a given brace-enclosed initializer is for a class type or for an - array. This function checks that CE does not use a designated - initializer. If it does, an error is issued. Returns true if CE - is valid, i.e., does not have a designated initializer. */ - -static bool -check_array_designated_initializer (const constructor_elt *ce) -{ - /* Designated initializers for array elements arenot supported. */ - if (ce->index) - { - /* The parser only allows identifiers as designated - intializers. */ - gcc_assert (TREE_CODE (ce->index) == IDENTIFIER_NODE); - error ("name %qD used in a GNU-style designated " - "initializer for an array", ce->index); - return false; - } - - return true; -} - /* When parsing `int a[] = {1, 2};' we don't know the size of the array until we finish parsing the initializer. If that's the situation we're in, update DECL accordingly. */ @@ -4182,55 +4011,27 @@ maybe_deduce_size_from_array_init (tree decl, tree init) But let's leave it here to ease the eventual merge. */ int do_default = !DECL_EXTERNAL (decl); tree initializer = init ? init : DECL_INITIAL (decl); - int failure = 0; + int failure = complete_array_type (type, initializer, do_default); - /* Check that there are no designated initializers in INIT, as - those are not supported in GNU C++, and as the middle-end - will crash if presented with a non-numeric designated - initializer. */ - if (initializer && TREE_CODE (initializer) == CONSTRUCTOR) - { - VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (initializer); - constructor_elt *ce; - HOST_WIDE_INT i; - for (i = 0; - VEC_iterate (constructor_elt, v, i, ce); - ++i) - if (!check_array_designated_initializer (ce)) - failure = 1; - } + if (failure == 1) + error ("initializer fails to determine size of `%D'", decl); - if (!failure) + if (failure == 2) { - failure = cp_complete_array_type (&TREE_TYPE (decl), initializer, - do_default); - if (failure == 1) - { - error ("initializer fails to determine size of %qD", decl); - TREE_TYPE (decl) = error_mark_node; - } - else if (failure == 2) - { - if (do_default) - { - error ("array size missing in %qD", decl); - TREE_TYPE (decl) = error_mark_node; - } - /* If a `static' var's size isn't known, make it extern as - well as static, so it does not get allocated. If it's not - `static', then don't mark it extern; finish_incomplete_decl - will give it a default size and it will get allocated. */ - else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl)) - DECL_EXTERNAL (decl) = 1; - } - else if (failure == 3) - { - error ("zero-size array %qD", decl); - TREE_TYPE (decl) = error_mark_node; - } + if (do_default) + error ("array size missing in `%D'", decl); + /* If a `static' var's size isn't known, make it extern as + well as static, so it does not get allocated. If it's not + `static', then don't mark it extern; finish_incomplete_decl + will give it a default size and it will get allocated. */ + else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl)) + DECL_EXTERNAL (decl) = 1; } - cp_apply_type_quals_to_decl (cp_type_quals (TREE_TYPE (decl)), decl); + if (pedantic && TYPE_DOMAIN (type) != NULL_TREE + && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + integer_zero_node)) + error ("zero-size array `%D'", decl); layout_decl (decl, 0); } @@ -4242,11 +4043,10 @@ maybe_deduce_size_from_array_init (tree decl, tree init) static void layout_var_decl (tree decl) { - tree type; - - type = TREE_TYPE (decl); - if (type == error_mark_node) - return; + tree type = TREE_TYPE (decl); +#if 0 + tree ttype = target_type (type); +#endif /* If we haven't already layed out this declaration, do so now. Note that we must not call complete type for an external object @@ -4255,10 +4055,10 @@ layout_var_decl (tree decl) `extern X x' for some incomplete type `X'.) */ if (!DECL_EXTERNAL (decl)) complete_type (type); - if (!DECL_SIZE (decl) + if (!DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node && (COMPLETE_TYPE_P (type) - || (TREE_CODE (type) == ARRAY_TYPE + || (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type) && COMPLETE_TYPE_P (TREE_TYPE (type))))) layout_decl (decl, 0); @@ -4268,7 +4068,7 @@ layout_var_decl (tree decl) /* An automatic variable with an incomplete type: that is an error. Don't talk about array types here, since we took care of that message in grokdeclarator. */ - error ("storage size of %qD isn't known", decl); + error ("storage size of `%D' isn't known", decl); TREE_TYPE (decl) = error_mark_node; } #if 0 @@ -4290,8 +4090,14 @@ layout_var_decl (tree decl) if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) constant_expression_warning (DECL_SIZE (decl)); else - error ("storage size of %qD isn't constant", decl); + error ("storage size of `%D' isn't constant", decl); } + + if (TREE_STATIC (decl) + && !DECL_ARTIFICIAL (decl) + && current_function_decl + && DECL_CONTEXT (decl) == current_function_decl) + push_local_name (decl); } /* If a local static variable is declared in an inline function, or if @@ -4309,7 +4115,7 @@ maybe_commonize_var (tree decl) && DECL_FUNCTION_SCOPE_P (decl) /* Unfortunately, import_export_decl has not always been called before the function is processed, so we cannot simply check - DECL_COMDAT. */ + DECL_COMDAT. */ && (DECL_COMDAT (DECL_CONTEXT (decl)) || ((DECL_DECLARED_INLINE_P (DECL_CONTEXT (decl)) || DECL_TEMPLATE_INSTANTIATION (DECL_CONTEXT (decl))) @@ -4339,11 +4145,8 @@ maybe_commonize_var (tree decl) be merged. */ TREE_PUBLIC (decl) = 0; DECL_COMMON (decl) = 0; - warning (0, "sorry: semantics of inline function static " - "data %q+#D are wrong (you'll wind up " - "with multiple copies)", decl); - warning (0, "%J you can work around this by removing " - "the initializer", + cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl); + warning ("%J you can work around this by removing the initializer", decl); } } @@ -4369,21 +4172,9 @@ check_for_uninitialized_const_var (tree decl) && CP_TYPE_CONST_P (type) && !TYPE_NEEDS_CONSTRUCTING (type) && !DECL_INITIAL (decl)) - error ("uninitialized const %qD", decl); + error ("uninitialized const `%D'", decl); } - -/* Structure holding the current initializer being processed by reshape_init. - CUR is a pointer to the current element being processed, END is a pointer - after the last element present in the initializer. */ -typedef struct reshape_iterator_t -{ - constructor_elt *cur; - constructor_elt *end; -} reshape_iter; - -static tree reshape_init_r (tree, reshape_iter *, bool); - /* FIELD is a FIELD_DECL or NULL. In the former case, the value returned is the next FIELD_DECL (possibly FIELD itself) that can be initialized. If there are no more such fields, the return value @@ -4401,204 +4192,132 @@ next_initializable_field (tree field) return field; } -/* Subroutine of reshape_init_array and reshape_init_vector, which does - the actual work. ELT_TYPE is the element type of the array. MAX_INDEX is an - INTEGER_CST representing the size of the array minus one (the maximum index), - or NULL_TREE if the array was declared without specifying the size. D is - the iterator within the constructor. */ +/* Subroutine of reshape_init. Reshape the constructor for an array. INITP + is the pointer to the old constructor list (to the CONSTRUCTOR_ELTS of + the CONSTRUCTOR we are processing), while NEW_INIT is the CONSTRUCTOR we + are building. + ELT_TYPE is the element type of the array. MAX_INDEX is an INTEGER_CST + representing the size of the array minus one (the maximum index), or + NULL_TREE if the array was declared without specifying the size. */ -static tree -reshape_init_array_1 (tree elt_type, tree max_index, reshape_iter *d) +static bool +reshape_init_array (tree elt_type, tree max_index, + tree *initp, tree new_init) { - tree new_init; bool sized_array_p = (max_index != NULL_TREE); unsigned HOST_WIDE_INT max_index_cst = 0; unsigned HOST_WIDE_INT index; - /* The initializer for an array is always a CONSTRUCTOR. */ - new_init = build_constructor (NULL_TREE, NULL); - if (sized_array_p) { - /* Minus 1 is used for zero sized arrays. */ - if (integer_all_onesp (max_index)) - return new_init; - if (host_integerp (max_index, 1)) max_index_cst = tree_low_cst (max_index, 1); /* sizetype is sign extended, not zero extended. */ else - max_index_cst = tree_low_cst (fold_convert (size_type_node, max_index), - 1); + max_index_cst = tree_low_cst (convert (size_type_node, max_index), 1); } /* Loop until there are no more initializers. */ for (index = 0; - d->cur != d->end && (!sized_array_p || index <= max_index_cst); + *initp && (!sized_array_p || index <= max_index_cst); ++index) { - tree elt_init; + tree element_init; + tree designated_index; - check_array_designated_initializer (d->cur); - elt_init = reshape_init_r (elt_type, d, /*first_initializer_p=*/false); - if (elt_init == error_mark_node) - return error_mark_node; - CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init), NULL_TREE, elt_init); - } - - return new_init; -} - -/* Subroutine of reshape_init_r, processes the initializers for arrays. - Parameters are the same of reshape_init_r. */ - -static tree -reshape_init_array (tree type, reshape_iter *d) -{ - tree max_index = NULL_TREE; - - gcc_assert (TREE_CODE (type) == ARRAY_TYPE); - - if (TYPE_DOMAIN (type)) - max_index = array_type_nelts (type); - - return reshape_init_array_1 (TREE_TYPE (type), max_index, d); -} - -/* Subroutine of reshape_init_r, processes the initializers for vectors. - Parameters are the same of reshape_init_r. */ - -static tree -reshape_init_vector (tree type, reshape_iter *d) -{ - tree max_index = NULL_TREE; - tree rtype; - - gcc_assert (TREE_CODE (type) == VECTOR_TYPE); - - if (COMPOUND_LITERAL_P (d->cur->value)) - { - tree value = d->cur->value; - if (!same_type_p (TREE_TYPE (value), type)) + element_init = reshape_init (elt_type, initp); + if (element_init == error_mark_node) + return false; + TREE_CHAIN (element_init) = CONSTRUCTOR_ELTS (new_init); + CONSTRUCTOR_ELTS (new_init) = element_init; + designated_index = TREE_PURPOSE (element_init); + if (designated_index) { - error ("invalid type %qT as initializer for a vector of type %qT", - TREE_TYPE (d->cur->value), type); - value = error_mark_node; + /* Handle array designated initializers (GNU extension). */ + if (TREE_CODE (designated_index) == IDENTIFIER_NODE) + { + error ("name `%D' used in a GNU-style designated " + "initializer for an array", designated_index); + TREE_PURPOSE (element_init) = NULL_TREE; + } + else + abort (); } - ++d->cur; - return value; } - /* For a vector, the representation type is a struct - containing a single member which is an array of the - appropriate size. */ - rtype = TYPE_DEBUG_REPRESENTATION_TYPE (type); - if (rtype && TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (rtype)))) - max_index = array_type_nelts (TREE_TYPE (TYPE_FIELDS (rtype))); - - return reshape_init_array_1 (TREE_TYPE (type), max_index, d); + return true; } -/* Subroutine of reshape_init_r, processes the initializers for classes - or union. Parameters are the same of reshape_init_r. */ +/* Undo the brace-elision allowed by [dcl.init.aggr] in a + brace-enclosed aggregate initializer. + + *INITP is one of a list of initializers describing a brace-enclosed + initializer for an entity of the indicated aggregate TYPE. It may + not presently match the shape of the TYPE; for example: + + struct S { int a; int b; }; + struct S a[] = { 1, 2, 3, 4 }; + + Here *INITP will point to TREE_LIST of four elements, rather than a + list of two elements, each itself a list of two elements. This + routine transforms INIT from the former form into the latter. The + revised initializer is returned. */ static tree -reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p) +reshape_init (tree type, tree *initp) { - tree field; + tree inits; + tree old_init; + tree old_init_value; tree new_init; + bool brace_enclosed_p; + bool string_init_p; - gcc_assert (CLASS_TYPE_P (type)); + old_init = *initp; + old_init_value = (TREE_CODE (*initp) == TREE_LIST + ? TREE_VALUE (*initp) : old_init); - /* The initializer for a class is always a CONSTRUCTOR. */ - new_init = build_constructor (NULL_TREE, NULL); - field = next_initializable_field (TYPE_FIELDS (type)); + my_friendly_assert (old_init_value, 20030723); - if (!field) + /* If the initializer is brace-enclosed, pull initializers from the + enclosed elements. Advance past the brace-enclosed initializer + now. */ + if (TREE_CODE (old_init_value) == CONSTRUCTOR + && TREE_TYPE (old_init_value) == NULL_TREE + && TREE_HAS_CONSTRUCTOR (old_init_value)) { - /* [dcl.init.aggr] - - An initializer for an aggregate member that is an - empty class shall have the form of an empty - initializer-list {}. */ - if (!first_initializer_p) - { - error ("initializer for %qT must be brace-enclosed", type); - return error_mark_node; - } - return new_init; + *initp = TREE_CHAIN (old_init); + TREE_CHAIN (old_init) = NULL_TREE; + inits = CONSTRUCTOR_ELTS (old_init_value); + initp = &inits; + brace_enclosed_p = true; } - - /* Loop through the initializable fields, gathering initializers. */ - while (d->cur != d->end) + else { - tree field_init; - - /* Handle designated initializers, as an extension. */ - if (d->cur->index) - { - field = lookup_field_1 (type, d->cur->index, /*want_type=*/false); - - if (!field || TREE_CODE (field) != FIELD_DECL) - { - error ("%qT has no non-static data member named %qD", type, - d->cur->index); - return error_mark_node; - } - } - - /* If we processed all the member of the class, we are done. */ - if (!field) - break; - - field_init = reshape_init_r (TREE_TYPE (field), d, - /*first_initializer_p=*/false); - CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init), field, field_init); - - /* [dcl.init.aggr] - - When a union is initialized with a brace-enclosed - initializer, the braces shall only contain an - initializer for the first member of the union. */ - if (TREE_CODE (type) == UNION_TYPE) - break; - - field = next_initializable_field (TREE_CHAIN (field)); + inits = NULL_TREE; + brace_enclosed_p = false; } - return new_init; -} - -/* Subroutine of reshape_init, which processes a single initializer (part of - a CONSTRUCTOR). TYPE is the type of the variable being initialized, D is the - iterator within the CONSTRUCTOR which points to the initializer to process. - FIRST_INITIALIZER_P is true if this is the first initializer of the - CONSTRUCTOR node. */ - -static tree -reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p) -{ - tree init = d->cur->value; - /* A non-aggregate type is always initialized with a single initializer. */ if (!CP_AGGREGATE_TYPE_P (type)) - { - /* It is invalid to initialize a non-aggregate type with a - brace-enclosed initializer. - We need to check for BRACE_ENCLOSED_INITIALIZER_P here because - of g++.old-deja/g++.mike/p7626.C: a pointer-to-member constant is - a CONSTRUCTOR (with a record type). */ - if (TREE_CODE (init) == CONSTRUCTOR - && BRACE_ENCLOSED_INITIALIZER_P (init)) /* p7626.C */ - { - error ("braces around scalar initializer for type %qT", type); - init = error_mark_node; - } - - d->cur++; - return init; - } + { + *initp = TREE_CHAIN (old_init); + TREE_CHAIN (old_init) = NULL_TREE; + /* It is invalid to initialize a non-aggregate type with a + brace-enclosed initializer. */ + if (brace_enclosed_p) + { + error ("brace-enclosed initializer used to initialize `%T'", + type); + if (TREE_CODE (old_init) == TREE_LIST) + TREE_VALUE (old_init) = error_mark_node; + else + old_init = error_mark_node; + } + + return old_init; + } /* [dcl.init.aggr] @@ -4609,130 +4328,127 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p) non-empty subaggregate, brace elision is assumed and the initializer is considered for the initialization of the first member of the subaggregate. */ - if (TREE_CODE (init) != CONSTRUCTOR - && can_convert_arg (type, TREE_TYPE (init), init, LOOKUP_NORMAL)) + if (!brace_enclosed_p + && can_convert_arg (type, TREE_TYPE (old_init_value), old_init_value)) { - d->cur++; - return init; + *initp = TREE_CHAIN (old_init); + TREE_CHAIN (old_init) = NULL_TREE; + return old_init; } - /* [dcl.init.string] - - A char array (whether plain char, signed char, or unsigned char) - can be initialized by a string-literal (optionally enclosed in - braces); a wchar_t array can be initialized by a wide - string-literal (optionally enclosed in braces). */ - if (TREE_CODE (type) == ARRAY_TYPE + string_init_p = false; + if (TREE_CODE (old_init_value) == STRING_CST + && TREE_CODE (type) == ARRAY_TYPE && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))) { - tree str_init = init; - - /* Strip one level of braces if and only if they enclose a single - element (as allowed by [dcl.init.string]). */ - if (!first_initializer_p - && TREE_CODE (str_init) == CONSTRUCTOR - && VEC_length (constructor_elt, CONSTRUCTOR_ELTS (str_init)) == 1) - { - str_init = VEC_index (constructor_elt, - CONSTRUCTOR_ELTS (str_init), 0)->value; - } + /* [dcl.init.string] - /* If it's a string literal, then it's the initializer for the array - as a whole. Otherwise, continue with normal initialization for - array types (one value per array element). */ - if (TREE_CODE (str_init) == STRING_CST) - { - d->cur++; - return str_init; - } + A char array (whether plain char, signed char, or unsigned char) + can be initialized by a string-literal (optionally enclosed in + braces); a wchar_t array can be initialized by a wide + string-literal (optionally enclosed in braces). */ + new_init = old_init; + /* Move past the initializer. */ + *initp = TREE_CHAIN (old_init); + TREE_CHAIN (old_init) = NULL_TREE; + string_init_p = true; } - - /* The following cases are about aggregates. If we are not within a full - initializer already, and there is not a CONSTRUCTOR, it means that there - is a missing set of braces (that is, we are processing the case for - which reshape_init exists). */ - if (!first_initializer_p) - { - if (TREE_CODE (init) == CONSTRUCTOR) - { - if (TREE_TYPE (init) && TYPE_PTRMEMFUNC_P (TREE_TYPE (init))) - /* There is no need to reshape pointer-to-member function - initializers, as they are always constructed correctly - by the front end. */ - ; - else if (COMPOUND_LITERAL_P (init)) - /* For a nested compound literal, there is no need to reshape since - brace elision is not allowed. Even if we decided to allow it, - we should add a call to reshape_init in finish_compound_literal, - before calling digest_init, so changing this code would still - not be necessary. */ - gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (init)); - else - { - ++d->cur; - gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (init)); - return reshape_init (type, init); - } - } - - warning (OPT_Wmissing_braces, "missing braces around initializer for %qT", - type); - } - - /* Dispatch to specialized routines. */ - if (CLASS_TYPE_P (type)) - return reshape_init_class (type, d, first_initializer_p); - else if (TREE_CODE (type) == ARRAY_TYPE) - return reshape_init_array (type, d); - else if (TREE_CODE (type) == VECTOR_TYPE) - return reshape_init_vector (type, d); else - gcc_unreachable(); -} - -/* Undo the brace-elision allowed by [dcl.init.aggr] in a - brace-enclosed aggregate initializer. - - INIT is the CONSTRUCTOR containing the list of initializers describing - a brace-enclosed initializer for an entity of the indicated aggregate TYPE. - It may not presently match the shape of the TYPE; for example: + { + /* Build a CONSTRUCTOR to hold the contents of the aggregate. */ + new_init = build_constructor (type, NULL_TREE); + TREE_HAS_CONSTRUCTOR (new_init) = 1; - struct S { int a; int b; }; - struct S a[] = { 1, 2, 3, 4 }; + if (CLASS_TYPE_P (type)) + { + tree field; - Here INIT will hold a VEC of four elements, rather than a - VEC of two elements, each itself a VEC of two elements. This - routine transforms INIT from the former form into the latter. The - revised CONSTRUCTOR node is returned. */ + field = next_initializable_field (TYPE_FIELDS (type)); -tree -reshape_init (tree type, tree init) -{ - VEC(constructor_elt, gc) *v; - reshape_iter d; - tree new_init; + if (!field) + { + /* [dcl.init.aggr] + + An initializer for an aggregate member that is an + empty class shall have the form of an empty + initializer-list {}. */ + if (!brace_enclosed_p) + { + error ("initializer for `%T' must be brace-enclosed", + type); + return error_mark_node; + } + } + else + { + /* Loop through the initializable fields, gathering + initializers. */ + while (*initp) + { + tree field_init; - gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (init)); + /* Handle designated initializers, as an extension. */ + if (TREE_PURPOSE (*initp)) + { + if (pedantic) + pedwarn ("ISO C++ does not allow designated initializers"); + field = lookup_field_1 (type, TREE_PURPOSE (*initp), + /*want_type=*/false); + if (!field || TREE_CODE (field) != FIELD_DECL) + error ("`%T' has no non-static data member named `%D'", + type, TREE_PURPOSE (*initp)); + } + if (!field) + break; - v = CONSTRUCTOR_ELTS (init); + field_init = reshape_init (TREE_TYPE (field), initp); + if (field_init == error_mark_node) + return error_mark_node; + TREE_CHAIN (field_init) = CONSTRUCTOR_ELTS (new_init); + CONSTRUCTOR_ELTS (new_init) = field_init; + /* [dcl.init.aggr] + + When a union is initialized with a brace-enclosed + initializer, the braces shall only contain an + initializer for the first member of the union. */ + if (TREE_CODE (type) == UNION_TYPE) + break; + field = next_initializable_field (TREE_CHAIN (field)); + } + } + } + else if ((TREE_CODE (type) == ARRAY_TYPE)|| (TREE_CODE (type) == VECTOR_TYPE)) + { + tree max_index; - /* An empty constructor does not need reshaping, and it is always a valid - initializer. */ - if (VEC_empty (constructor_elt, v)) - return init; + /* If the bound of the array is known, take no more initializers + than are allowed. */ + max_index = ((TYPE_DOMAIN (type) && (TREE_CODE (type) == ARRAY_TYPE)) + ? array_type_nelts (type) : NULL_TREE); + if (!reshape_init_array (TREE_TYPE (type), max_index, + initp, new_init)) + return error_mark_node; + } + else + abort (); - /* Recurse on this CONSTRUCTOR. */ - d.cur = VEC_index (constructor_elt, v, 0); - d.end = d.cur + VEC_length (constructor_elt, v); + /* The initializers were placed in reverse order in the + CONSTRUCTOR. */ + CONSTRUCTOR_ELTS (new_init) = nreverse (CONSTRUCTOR_ELTS (new_init)); - new_init = reshape_init_r (type, &d, true); - if (new_init == error_mark_node) - return error_mark_node; + if (TREE_CODE (old_init) == TREE_LIST) + new_init = build_tree_list (TREE_PURPOSE (old_init), new_init); + } - /* Make sure all the element of the constructor were used. Otherwise, - issue an error about exceeding initializers. */ - if (d.cur != d.end) - error ("too many initializers for %qT", type); + /* If there are more initializers than necessary, issue a + diagnostic. */ + if (*initp) + { + if (brace_enclosed_p) + error ("too many initializers for `%T'", type); + else if (warn_missing_braces && !string_init_p) + warning ("missing braces around initializer"); + } return new_init; } @@ -4750,74 +4466,68 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) tree type = TREE_TYPE (decl); tree init_code = NULL; + /* If `start_decl' didn't like having an initialization, ignore it now. */ + if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE) + init = NULL_TREE; + + /* If an initializer is present, DECL_INITIAL has been + error_mark_node, to indicate that an as-of-yet unevaluated + initialization will occur. From now on, DECL_INITIAL reflects + the static initialization -- if any -- of DECL. */ + DECL_INITIAL (decl) = NULL_TREE; + /* Things that are going to be initialized need to have complete type. */ TREE_TYPE (decl) = type = complete_type (TREE_TYPE (decl)); if (type == error_mark_node) /* We will have already complained. */ - return NULL_TREE; - - if (TREE_CODE (type) == ARRAY_TYPE) + init = NULL_TREE; + else if (init && COMPLETE_TYPE_P (type) + && !TREE_CONSTANT (TYPE_SIZE (type))) { - tree element_type = TREE_TYPE (type); - - /* The array type itself need not be complete, because the - initializer may tell us how many elements are in the array. - But, the elements of the array must be complete. */ - if (!COMPLETE_TYPE_P (complete_type (element_type))) - { - error ("elements of array %q#D have incomplete type", decl); - return NULL_TREE; - } - /* It is not valid to initialize an a VLA. */ - if (init - && ((COMPLETE_TYPE_P (type) && !TREE_CONSTANT (TYPE_SIZE (type))) - || !TREE_CONSTANT (TYPE_SIZE (element_type)))) - { - error ("variable-sized object %qD may not be initialized", decl); - return NULL_TREE; - } + error ("variable-sized object `%D' may not be initialized", decl); + init = NULL_TREE; } - else if (!COMPLETE_TYPE_P (type)) + else if (TREE_CODE (type) == ARRAY_TYPE + && !COMPLETE_TYPE_P (complete_type (TREE_TYPE (type)))) { - error ("%qD has incomplete type", decl); - TREE_TYPE (decl) = error_mark_node; - return NULL_TREE; + error ("elements of array `%#D' have incomplete type", decl); + init = NULL_TREE; } - else - /* There is no way to make a variable-sized class type in GNU C++. */ - gcc_assert (TREE_CONSTANT (TYPE_SIZE (type))); - - if (!CP_AGGREGATE_TYPE_P (type) - && init && BRACE_ENCLOSED_INITIALIZER_P (init) - && VEC_length (constructor_elt, CONSTRUCTOR_ELTS (init)) != 1) + else if (TREE_CODE (type) != ARRAY_TYPE && !COMPLETE_TYPE_P (type)) { - error ("scalar object %qD requires one element in initializer", decl); + error ("`%D' has incomplete type", decl); TREE_TYPE (decl) = error_mark_node; - return NULL_TREE; + init = NULL_TREE; } if (TREE_CODE (decl) == CONST_DECL) { - gcc_assert (TREE_CODE (type) != REFERENCE_TYPE); + my_friendly_assert (TREE_CODE (decl) != REFERENCE_TYPE, 148); DECL_INITIAL (decl) = init; - gcc_assert (init != NULL_TREE); + my_friendly_assert (init != NULL_TREE, 149); init = NULL_TREE; } else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE) init = grok_reference_init (decl, type, init, cleanup); else if (init) { - /* Do not reshape constructors of vectors (they don't need to be - reshaped. */ - if (TREE_CODE (init) == CONSTRUCTOR - && !COMPOUND_LITERAL_P (init) - && !TREE_TYPE (init)) /* ptrmemfunc */ + if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init)) { - init = reshape_init (type, init); + /* [dcl.init] paragraph 13, + If T is a scalar type, then a declaration of the form + T x = { a }; + is equivalent to + T x = a; + + reshape_init will complain about the extra braces, + and doesn't do anything useful in the case where TYPE is + scalar, so just don't call it. */ + if (CP_AGGREGATE_TYPE_P (type)) + init = reshape_init (type, &init); if ((*targetm.vector_opaque_p) (type)) { @@ -4830,19 +4540,19 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) array size from the initializer. */ maybe_deduce_size_from_array_init (decl, init); type = TREE_TYPE (decl); - if (type == error_mark_node) - return NULL_TREE; + if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init)) + TREE_TYPE (init) = type; if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type)) { if (TREE_CODE (type) == ARRAY_TYPE) goto initialize_aggr; - else if (TREE_CODE (init) == CONSTRUCTOR) + else if (TREE_CODE (init) == CONSTRUCTOR + && TREE_HAS_CONSTRUCTOR (init)) { if (TYPE_NON_AGGREGATE_CLASS (type)) { - error ("%qD must be initialized by constructor, " - "not by %<{...}%>", + error ("`%D' must be initialized by constructor, not by `{...}'", decl); init = error_mark_node; } @@ -4873,12 +4583,6 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) if (TREE_CODE (init) != TREE_VEC) { init_code = store_init_value (decl, init); - if (pedantic && TREE_CODE (type) == ARRAY_TYPE - && DECL_INITIAL (decl) - && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST - && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl))) - warning (0, "array %qD initialized by parenthesized string literal %qE", - decl, DECL_INITIAL (decl)); init = NULL; } } @@ -4892,9 +4596,10 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) tree core_type = strip_array_types (type); if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type)) - error ("structure %qD with uninitialized const members", decl); + error ("structure `%D' with uninitialized const members", decl); if (CLASSTYPE_REF_FIELDS_NEED_INIT (core_type)) - error ("structure %qD with uninitialized reference members", decl); + error ("structure `%D' with uninitialized reference members", + decl); check_for_uninitialized_const_var (decl); } @@ -4902,7 +4607,7 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) check_for_uninitialized_const_var (decl); if (init && init != error_mark_node) - init_code = build2 (INIT_EXPR, type, decl, init); + init_code = build (INIT_EXPR, type, decl, init); return init_code; } @@ -4914,32 +4619,11 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec) { int toplev = toplevel_bindings_p (); int defer_p; - const char *filename; - - /* Set the DECL_ASSEMBLER_NAME for the object. */ - if (asmspec) - { - /* The `register' keyword, when used together with an - asm-specification, indicates that the variable should be - placed in a particular register. */ - if (TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)) - { - set_user_assembler_name (decl, asmspec); - DECL_HARD_REGISTER (decl) = 1; - } - else - { - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL) - set_builtin_user_assembler_name (decl, asmspec); - set_user_assembler_name (decl, asmspec); - } - } /* Handle non-variables up front. */ if (TREE_CODE (decl) != VAR_DECL) { - rest_of_decl_compilation (decl, toplev, at_eof); + rest_of_decl_compilation (decl, asmspec, toplev, at_eof); return; } @@ -4947,11 +4631,22 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec) member. */ if (DECL_LANG_SPECIFIC (decl) && DECL_IN_AGGR_P (decl)) { - gcc_assert (TREE_STATIC (decl)); + my_friendly_assert (TREE_STATIC (decl), 19990828); /* An in-class declaration of a static data member should be external; it is only a declaration, and not a definition. */ if (init == NULL_TREE) - gcc_assert (DECL_EXTERNAL (decl)); + my_friendly_assert (DECL_EXTERNAL (decl), 20000723); + } + + /* Set the DECL_ASSEMBLER_NAME for the variable. */ + if (asmspec) + { + change_decl_assembler_name (decl, get_identifier (asmspec)); + /* The `register' keyword, when used together with an + asm-specification, indicates that the variable should be + placed in a particular register. */ + if (DECL_REGISTER (decl)) + DECL_C_HARD_REGISTER (decl) = 1; } /* We don't create any RTL for local variables. */ @@ -4959,40 +4654,43 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec) return; /* We defer emission of local statics until the corresponding - DECL_EXPR is expanded. */ + DECL_STMT is expanded. */ defer_p = DECL_FUNCTION_SCOPE_P (decl) || DECL_VIRTUAL_P (decl); /* We try to defer namespace-scope static constants so that they are not emitted into the object file unnecessarily. */ - filename = input_filename; if (!DECL_VIRTUAL_P (decl) && TREE_READONLY (decl) && DECL_INITIAL (decl) != NULL_TREE && DECL_INITIAL (decl) != error_mark_node - && filename != NULL && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)) && toplev && !TREE_PUBLIC (decl)) { /* Fool with the linkage of static consts according to #pragma interface. */ - struct c_fileinfo *finfo = get_fileinfo (filename); - if (!finfo->interface_unknown && !TREE_PUBLIC (decl)) + if (!interface_unknown && !TREE_PUBLIC (decl)) { TREE_PUBLIC (decl) = 1; - DECL_EXTERNAL (decl) = finfo->interface_only; + DECL_EXTERNAL (decl) = interface_only; } defer_p = 1; } /* Likewise for template instantiations. */ - else if (DECL_LANG_SPECIFIC (decl) - && DECL_IMPLICIT_INSTANTIATION (decl)) + else if (DECL_COMDAT (decl)) defer_p = 1; + /* If we're deferring the variable, we only need to make RTL if + there's an ASMSPEC. Otherwise, we'll lazily create it later when + we need it. (There's no way to lazily create RTL for things that + have assembly specs because the information about the specifier + isn't stored in the tree, yet) */ + if (defer_p && asmspec) + make_decl_rtl (decl, asmspec); /* If we're not deferring, go ahead and assemble the variable. */ - if (!defer_p) - rest_of_decl_compilation (decl, toplev, at_eof); + else if (!defer_p) + rest_of_decl_compilation (decl, asmspec, toplev, at_eof); } /* Generate code to initialize DECL (a local variable). */ @@ -5003,9 +4701,10 @@ initialize_local_var (tree decl, tree init) tree type = TREE_TYPE (decl); tree cleanup; - gcc_assert (TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == RESULT_DECL); - gcc_assert (!TREE_STATIC (decl)); + my_friendly_assert (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == RESULT_DECL, + 20021010); + my_friendly_assert (!TREE_STATIC (decl), 20021010); if (DECL_SIZE (decl) == NULL_TREE) { @@ -5026,7 +4725,7 @@ initialize_local_var (tree decl, tree init) { int saved_stmts_are_full_exprs_p; - gcc_assert (building_stmt_tree ()); + my_friendly_assert (building_stmt_tree (), 20000906); saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); current_stmt_tree ()->stmts_are_full_exprs_p = 1; finish_expr_stmt (init); @@ -5055,48 +4754,26 @@ initialize_local_var (tree decl, tree init) finish_decl_cleanup (decl, cleanup); } -/* DECL is a VAR_DECL for a compiler-generated variable with static - storage duration (like a virtual table) whose initializer is a - compile-time constant. INIT must be either a TREE_LIST of values, - or a CONSTRUCTOR. Initialize the variable and provide it to the - back end. */ - -void -initialize_artificial_var (tree decl, tree init) -{ - gcc_assert (DECL_ARTIFICIAL (decl)); - if (TREE_CODE (init) == TREE_LIST) - init = build_constructor_from_list (NULL_TREE, init); - gcc_assert (TREE_CODE (init) == CONSTRUCTOR); - DECL_INITIAL (decl) = init; - DECL_INITIALIZED_P (decl) = 1; - determine_visibility (decl); - layout_var_decl (decl); - maybe_commonize_var (decl); - make_rtl_for_nonlocal_decl (decl, init, /*asmspec=*/NULL); -} - /* Finish processing of a declaration; install its line number and initial value. If the length of an array type is not known before, it must be determined now, from the initial value, or it is an error. - INIT is the initializer (if any) for DECL. If INIT_CONST_EXPR_P is - true, then INIT is an integral constant expression. + INIT holds the value of an initializer that should be allowed to escape + the normal rules. FLAGS is LOOKUP_ONLYCONVERTING if the = init syntax was used, else 0 if the (init) syntax was used. */ void -cp_finish_decl (tree decl, tree init, bool init_const_expr_p, - tree asmspec_tree, int flags) +cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags) { tree type; + tree ttype = NULL_TREE; tree cleanup; const char *asmspec = NULL; int was_readonly = 0; bool var_definition_p = false; - int saved_processing_template_decl; if (decl == error_mark_node) return; @@ -5107,73 +4784,66 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, return; } - gcc_assert (TREE_CODE (decl) != RESULT_DECL); - /* Parameters are handled by store_parm_decls, not cp_finish_decl. */ - gcc_assert (TREE_CODE (decl) != PARM_DECL); - - type = TREE_TYPE (decl); - if (type == error_mark_node) - return; + my_friendly_assert (TREE_CODE (decl) != RESULT_DECL, 20030619); /* Assume no cleanup is required. */ cleanup = NULL_TREE; - saved_processing_template_decl = processing_template_decl; /* If a name was specified, get the string. */ if (global_scope_p (current_binding_level)) asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree); - if (asmspec_tree && asmspec_tree != error_mark_node) + if (asmspec_tree) asmspec = TREE_STRING_POINTER (asmspec_tree); + if (init && TREE_CODE (init) == NAMESPACE_DECL) + { + error ("cannot initialize `%D' to namespace `%D'", + decl, init); + init = NULL_TREE; + } + if (current_class_type && CP_DECL_CONTEXT (decl) == current_class_type && TYPE_BEING_DEFINED (current_class_type) && (DECL_INITIAL (decl) || init)) DECL_INITIALIZED_IN_CLASS_P (decl) = 1; - if (processing_template_decl) + if (TREE_CODE (decl) == VAR_DECL + && DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL + && DECL_CONTEXT (decl) != current_namespace + && init) { - bool type_dependent_p; + /* Leave the namespace of the object. */ + pop_decl_namespace (); + } - /* Add this declaration to the statement-tree. */ - if (at_function_scope_p ()) - add_decl_expr (decl); + type = TREE_TYPE (decl); - type_dependent_p = dependent_type_p (type); + if (type == error_mark_node) + goto finish_end0; - if (init && init_const_expr_p) - { - DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1; - if (DECL_INTEGRAL_CONSTANT_VAR_P (decl)) - TREE_CONSTANT (decl) = 1; - } + if (TYPE_HAS_MUTABLE_P (type)) + TREE_READONLY (decl) = 0; - if (!init - || !DECL_CLASS_SCOPE_P (decl) - || !DECL_INTEGRAL_CONSTANT_VAR_P (decl) - || type_dependent_p - || value_dependent_expression_p (init) - /* Check also if initializer is a value dependent - { integral_constant_expression }. */ - || (TREE_CODE (init) == CONSTRUCTOR - && VEC_length (constructor_elt, CONSTRUCTOR_ELTS (init)) == 1 - && value_dependent_expression_p - (VEC_index (constructor_elt, - CONSTRUCTOR_ELTS (init), 0)->value))) - { - if (init) - DECL_INITIAL (decl) = init; - if (TREE_CODE (decl) == VAR_DECL - && !DECL_PRETTY_FUNCTION_P (decl) - && !type_dependent_p) - maybe_deduce_size_from_array_init (decl, init); - goto finish_end; - } + if (processing_template_decl) + { + /* Add this declaration to the statement-tree. */ + if (at_function_scope_p ()) + add_decl_stmt (decl); - init = fold_non_dependent_expr (init); - processing_template_decl = 0; + if (init && DECL_INITIAL (decl)) + DECL_INITIAL (decl) = init; + if (TREE_CODE (decl) == VAR_DECL + && !DECL_PRETTY_FUNCTION_P (decl) + && !dependent_type_p (TREE_TYPE (decl))) + maybe_deduce_size_from_array_init (decl, init); + goto finish_end0; } + /* Parameters are handled by store_parm_decls, not cp_finish_decl. */ + my_friendly_assert (TREE_CODE (decl) != PARM_DECL, 19990828); + /* Take care of TYPE_DECLs up front. */ if (TREE_CODE (decl) == TYPE_DECL) { @@ -5181,7 +4851,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, && IS_AGGR_TYPE (type) && DECL_NAME (decl)) { if (TREE_TYPE (DECL_NAME (decl)) && TREE_TYPE (decl) != type) - warning (0, "shadowing previous type declaration of %q#D", decl); + warning ("shadowing previous type declaration of `%#D'", decl); set_identifier_type_value (DECL_NAME (decl), decl); } @@ -5192,38 +4862,34 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, && !COMPLETE_TYPE_P (TREE_TYPE (decl))) TYPE_DECL_SUPPRESS_DEBUG (decl) = 1; - rest_of_decl_compilation (decl, DECL_CONTEXT (decl) == NULL_TREE, - at_eof); + rest_of_decl_compilation (decl, NULL, + DECL_CONTEXT (decl) == NULL_TREE, at_eof); goto finish_end; } - /* A reference will be modified here, as it is initialized. */ - if (! DECL_EXTERNAL (decl) - && TREE_READONLY (decl) - && TREE_CODE (type) == REFERENCE_TYPE) + if (TREE_CODE (decl) != FUNCTION_DECL) + ttype = target_type (type); + + + /* Currently, GNU C++ puts constants in text space, making them + impossible to initialize. In the future, one would hope for + an operating system which understood the difference between + initialization and the running of a program. */ + if (! DECL_EXTERNAL (decl) && TREE_READONLY (decl)) { was_readonly = 1; - TREE_READONLY (decl) = 0; + if (TYPE_NEEDS_CONSTRUCTING (type) + || TREE_CODE (type) == REFERENCE_TYPE) + TREE_READONLY (decl) = 0; } if (TREE_CODE (decl) == VAR_DECL) { /* Only PODs can have thread-local storage. Other types may require various kinds of non-trivial initialization. */ - if (DECL_THREAD_LOCAL_P (decl) && !pod_type_p (TREE_TYPE (decl))) - error ("%qD cannot be thread-local because it has non-POD type %qT", + if (DECL_THREAD_LOCAL (decl) && !pod_type_p (TREE_TYPE (decl))) + error ("`%D' cannot be thread-local because it has non-POD type `%T'", decl, TREE_TYPE (decl)); - /* If this is a local variable that will need a mangled name, - register it now. We must do this before processing the - initializer for the variable, since the initialization might - require a guard variable, and since the mangled name of the - guard variable will depend on the mangled name of this - variable. */ - if (!processing_template_decl - && DECL_FUNCTION_SCOPE_P (decl) - && TREE_STATIC (decl) - && !DECL_ARTIFICIAL (decl)) - push_local_name (decl); /* Convert the initializer to the type of DECL, if we have not already initialized DECL. */ if (!DECL_INITIALIZED_P (decl) @@ -5233,52 +4899,32 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, is *not* defined. */ && (!DECL_EXTERNAL (decl) || init)) { - if (init) - { - DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1; - if (init_const_expr_p) - { - DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1; - if (DECL_INTEGRAL_CONSTANT_VAR_P (decl)) - TREE_CONSTANT (decl) = 1; - } - } init = check_initializer (decl, init, flags, &cleanup); /* Thread-local storage cannot be dynamically initialized. */ - if (DECL_THREAD_LOCAL_P (decl) && init) + if (DECL_THREAD_LOCAL (decl) && init) { - error ("%qD is thread-local and so cannot be dynamically " + error ("`%D' is thread-local and so cannot be dynamically " "initialized", decl); init = NULL_TREE; } - - /* Check that the initializer for a static data member was a - constant. Although we check in the parser that the - initializer is an integral constant expression, we do not - simplify division-by-zero at the point at which it - occurs. Therefore, in: - - struct S { static const int i = 7 / 0; }; - - we issue an error at this point. It would - probably be better to forbid division by zero in - integral constant expressions. */ if (DECL_EXTERNAL (decl) && init) { - error ("%qD cannot be initialized by a non-constant expression" + /* The static data member cannot be initialized by a + non-constant when being declared. */ + error ("`%D' cannot be initialized by a non-constant expression" " when being declared", decl); DECL_INITIALIZED_IN_CLASS_P (decl) = 0; init = NULL_TREE; } - + /* Handle: - + [dcl.init] - + The memory occupied by any object of static storage duration is zero-initialized at program startup before any other initialization takes place. - + We cannot create an appropriate initializer until after the type of DECL is finalized. If DECL_INITIAL is set, then the DECL is statically initialized, and any @@ -5305,38 +4951,43 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, } /* Add this declaration to the statement-tree. This needs to happen - after the call to check_initializer so that the DECL_EXPR for a - reference temp is added before the DECL_EXPR for the reference itself. */ + after the call to check_initializer so that the DECL_STMT for a + reference temp is added before the DECL_STMT for the reference itself. */ if (at_function_scope_p ()) - add_decl_expr (decl); + add_decl_stmt (decl); + + if (TREE_CODE (decl) == VAR_DECL) + layout_var_decl (decl); - /* Let the middle end know about variables and functions -- but not - static data members in uninstantiated class templates. */ - if (!saved_processing_template_decl - && (TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL)) + /* Output the assembler code and/or RTL code for variables and functions, + unless the type is an undefined structure or union. + If not, it will get done when the type is completed. */ + if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL) { if (TREE_CODE (decl) == VAR_DECL) - { - layout_var_decl (decl); - maybe_commonize_var (decl); - } + maybe_commonize_var (decl); make_rtl_for_nonlocal_decl (decl, init, asmspec); - /* Check for abstractness of the type. Notice that there is no - need to strip array types here since the check for those types - is already done within create_array_type_for_decl. */ if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) - abstract_virtuals_error (decl, TREE_TYPE (type)); + abstract_virtuals_error (decl, + strip_array_types (TREE_TYPE (type))); + else if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) + { + /* If it's either a pointer or an array type, strip through all + of them but the last one. If the last is an array type, issue + an error if the element type is abstract. */ + while (POINTER_TYPE_P (TREE_TYPE (type)) + || TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE) + type = TREE_TYPE (type); + if (TREE_CODE (type) == ARRAY_TYPE) + abstract_virtuals_error (decl, TREE_TYPE (type)); + } else abstract_virtuals_error (decl, type); - /* This needs to happen after the linkage is set. */ - determine_visibility (decl); - - if (TREE_CODE (decl) == FUNCTION_DECL + if (TREE_CODE (decl) == FUNCTION_DECL || TREE_TYPE (decl) == error_mark_node) /* No initialization required. */ ; @@ -5352,15 +5003,20 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, /* A variable definition. */ if (DECL_FUNCTION_SCOPE_P (decl)) { + /* This is a local declaration. */ + maybe_inject_for_scope_var (decl); /* Initialize the local variable. */ if (processing_template_decl) - DECL_INITIAL (decl) = init; + { + if (init || DECL_INITIAL (decl) == error_mark_node) + DECL_INITIAL (decl) = init; + } else if (!TREE_STATIC (decl)) initialize_local_var (decl, init); } /* If a variable is defined, and then a subsequent - definition with external linkage is encountered, we will + definintion with external linkage is encountered, we will get here twice for the same variable. We want to avoid calling expand_static_init more than once. For variables that are not static data members, we can call @@ -5368,24 +5024,43 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, initializer. It is not legal to redeclare a static data member, so this issue does not arise in that case. */ if (var_definition_p && TREE_STATIC (decl)) - expand_static_init (decl, init); + expand_static_init (decl, init); } + finish_end0: + + /* Undo call to `pushclass' that was done in `start_decl' + due to initialization of qualified member variable. + I.e., Foo::x = 10; */ + { + tree context = CP_DECL_CONTEXT (decl); + if (context + && TYPE_P (context) + && (TREE_CODE (decl) == VAR_DECL + /* We also have a pushclass done that we need to undo here + if we're at top level and declare a method. */ + || TREE_CODE (decl) == FUNCTION_DECL) + /* If size hasn't been set, we're still defining it, + and therefore inside the class body; don't pop + the binding level.. */ + && COMPLETE_TYPE_P (context) + && context == current_class_type) + pop_nested_class (); + } } /* If a CLEANUP_STMT was created to destroy a temporary bound to a reference, insert it in the statement-tree now. */ if (cleanup) - push_cleanup (decl, cleanup, false); + add_stmt (cleanup); finish_end: - processing_template_decl = saved_processing_template_decl; if (was_readonly) TREE_READONLY (decl) = 1; /* If this was marked 'used', be sure it will be output. */ if (lookup_attribute ("used", DECL_ATTRIBUTES (decl))) - mark_decl_referenced (decl); + mark_referenced (DECL_ASSEMBLER_NAME (decl)); } /* This is here for a midend callback from c-common.c. */ @@ -5393,7 +5068,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, void finish_decl (tree decl, tree init, tree asmspec_tree) { - cp_finish_decl (decl, init, /*init_const_expr_p=*/false, asmspec_tree, 0); + cp_finish_decl (decl, init, asmspec_tree, 0); } /* Returns a declaration for a VAR_DECL as if: @@ -5403,7 +5078,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree) had been seen. Used to create compiler-generated global variables. */ -static tree +tree declare_global_var (tree name, tree type) { tree decl; @@ -5413,12 +5088,8 @@ declare_global_var (tree name, tree type) TREE_PUBLIC (decl) = 1; DECL_EXTERNAL (decl) = 1; DECL_ARTIFICIAL (decl) = 1; - /* If the user has explicitly declared this variable (perhaps - because the code we are compiling is part of a low-level runtime - library), then it is possible that our declaration will be merged - with theirs by pushdecl. */ - decl = pushdecl (decl); - finish_decl (decl, NULL_TREE, NULL_TREE); + pushdecl (decl); + cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0); pop_from_top_level (); return decl; @@ -5436,7 +5107,6 @@ get_atexit_node (void) tree fn_type; tree fn_ptr_type; const char *name; - bool use_aeabi_atexit; if (atexit_node) return atexit_node; @@ -5450,7 +5120,6 @@ get_atexit_node (void) We build up the argument types and then then function type itself. */ - use_aeabi_atexit = targetm.cxx.use_aeabi_atexit (); /* First, build the pointer-to-function type for the first argument. */ arg_types = tree_cons (NULL_TREE, ptr_type_node, void_list_node); @@ -5458,29 +5127,18 @@ get_atexit_node (void) fn_ptr_type = build_pointer_type (fn_type); /* Then, build the rest of the argument types. */ arg_types = tree_cons (NULL_TREE, ptr_type_node, void_list_node); - if (use_aeabi_atexit) - { - arg_types = tree_cons (NULL_TREE, fn_ptr_type, arg_types); - arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types); - } - else - { - arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types); - arg_types = tree_cons (NULL_TREE, fn_ptr_type, arg_types); - } + arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types); + arg_types = tree_cons (NULL_TREE, fn_ptr_type, arg_types); /* And the final __cxa_atexit type. */ fn_type = build_function_type (integer_type_node, arg_types); fn_ptr_type = build_pointer_type (fn_type); - if (use_aeabi_atexit) - name = "__aeabi_atexit"; - else - name = "__cxa_atexit"; + name = "__cxa_atexit"; } else { /* The declaration for `atexit' is: - int atexit (void (*)()); + int atexit (void (*)()); We build up the argument types and then then function type itself. */ @@ -5525,6 +5183,8 @@ static GTY(()) int start_cleanup_cnt; static tree start_cleanup_fn (void) { + int old_interface_only = interface_only; + int old_interface_unknown = interface_unknown; char name[32]; tree parmtypes; tree fntype; @@ -5535,6 +5195,9 @@ start_cleanup_fn (void) /* No need to mangle this. */ push_lang_context (lang_name_c); + interface_only = 0; + interface_unknown = 1; + /* Build the parameter-types. */ parmtypes = void_list_node; /* Functions passed to __cxa_atexit take an additional parameter. @@ -5572,7 +5235,10 @@ start_cleanup_fn (void) } pushdecl (fndecl); - start_preparsed_function (fndecl, NULL_TREE, SF_PRE_PARSED); + start_function (/*specs=*/NULL_TREE, fndecl, NULL_TREE, SF_PRE_PARSED); + + interface_unknown = old_interface_unknown; + interface_only = old_interface_only; pop_lang_context (); @@ -5592,7 +5258,7 @@ end_cleanup_fn (void) /* Generate code to handle the destruction of DECL, an object with static storage duration. */ -tree +void register_dtor_fn (tree decl) { tree cleanup; @@ -5601,7 +5267,7 @@ register_dtor_fn (tree decl) tree fcall; if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl))) - return void_zero_node; + return; /* Call build_cleanup before we enter the anonymous function so that any access checks will be done relative to the current scope, @@ -5615,13 +5281,13 @@ register_dtor_fn (tree decl) to the original function, rather than the anonymous one. That will make the back-end think that nested functions are in use, which causes confusion. */ - + push_deferring_access_checks (dk_no_check); fcall = build_cleanup (decl); pop_deferring_access_checks (); /* Create the body of the anonymous function. */ - compound_stmt = begin_compound_stmt (BCS_FN_BODY); + compound_stmt = begin_compound_stmt (/*has_no_scope=*/false); finish_expr_stmt (fcall); finish_compound_stmt (compound_stmt); end_cleanup_fn (); @@ -5632,23 +5298,15 @@ register_dtor_fn (tree decl) cleanup = build_unary_op (ADDR_EXPR, cleanup, 0); if (flag_use_cxa_atexit) { - args = tree_cons (NULL_TREE, + args = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, get_dso_handle_node (), 0), NULL_TREE); - if (targetm.cxx.use_aeabi_atexit ()) - { - args = tree_cons (NULL_TREE, cleanup, args); - args = tree_cons (NULL_TREE, null_pointer_node, args); - } - else - { - args = tree_cons (NULL_TREE, null_pointer_node, args); - args = tree_cons (NULL_TREE, cleanup, args); - } + args = tree_cons (NULL_TREE, null_pointer_node, args); + args = tree_cons (NULL_TREE, cleanup, args); } else args = tree_cons (NULL_TREE, cleanup, NULL_TREE); - return build_function_call (get_atexit_node (), args); + finish_expr_stmt (build_function_call (get_atexit_node (), args)); } /* DECL is a VAR_DECL with static storage duration. INIT, if present, @@ -5658,41 +5316,35 @@ register_dtor_fn (tree decl) static void expand_static_init (tree decl, tree init) { - gcc_assert (TREE_CODE (decl) == VAR_DECL); - gcc_assert (TREE_STATIC (decl)); + my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 20021010); + my_friendly_assert (TREE_STATIC (decl), 20021010); /* Some variables require no initialization. */ - if (!init + if (!init && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)) && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl))) return; - if (DECL_FUNCTION_SCOPE_P (decl)) + if (! toplevel_bindings_p ()) { /* Emit code to perform this initialization but once. */ - tree if_stmt = NULL_TREE, inner_if_stmt = NULL_TREE; - tree then_clause = NULL_TREE, inner_then_clause = NULL_TREE; - tree guard, guard_addr, guard_addr_list; - tree acquire_fn, release_fn, abort_fn; - tree flag, begin; + tree if_stmt; + tree then_clause; + tree assignment; + tree guard; + tree guard_init; /* Emit code to perform this initialization but once. This code looks like: - static <type> guard; - if (!guard.first_byte) { - if (__cxa_guard_acquire (&guard)) { - bool flag = false; - try { - // Do initialization. - flag = true; __cxa_guard_release (&guard); - // Register variable for destruction at end of program. - } catch { - if (!flag) __cxa_guard_abort (&guard); - } + static int guard = 0; + if (!guard) { + // Do initialization. + guard = 1; + // Register variable for destruction at end of program. } - Note that the `flag' variable is only set to 1 *after* the + Note that the `temp' variable is only set to 1 *after* the initialization is complete. This ensures that an exception, thrown during the construction, will cause the variable to reinitialized when we pass through this code again, as per: @@ -5703,145 +5355,161 @@ expand_static_init (tree decl, tree init) initialization is not complete, so it will be tried again the next time control enters the declaration. - This process should be thread-safe, too; multiple threads - should not be able to initialize the variable more than - once. */ + In theory, this process should be thread-safe, too; multiple + threads should not be able to initialize the variable more + than once. We don't yet attempt to ensure thread-safety. */ /* Create the guard variable. */ guard = get_guard (decl); - /* This optimization isn't safe on targets with relaxed memory - consistency. On such targets we force synchronization in - __cxa_guard_acquire. */ - if (!targetm.relaxed_ordering || !flag_threadsafe_statics) - { - /* Begin the conditional initialization. */ - if_stmt = begin_if_stmt (); - finish_if_stmt_cond (get_guard_cond (guard), if_stmt); - then_clause = begin_compound_stmt (BCS_NO_SCOPE); - } - - if (flag_threadsafe_statics) - { - guard_addr = build_address (guard); - guard_addr_list = build_tree_list (NULL_TREE, guard_addr); - - acquire_fn = get_identifier ("__cxa_guard_acquire"); - release_fn = get_identifier ("__cxa_guard_release"); - abort_fn = get_identifier ("__cxa_guard_abort"); - if (!get_global_value_if_present (acquire_fn, &acquire_fn)) - { - tree argtypes = tree_cons (NULL_TREE, TREE_TYPE (guard_addr), - void_list_node); - tree vfntype = build_function_type (void_type_node, argtypes); - acquire_fn = push_library_fn - (acquire_fn, build_function_type (integer_type_node, argtypes)); - release_fn = push_library_fn (release_fn, vfntype); - abort_fn = push_library_fn (abort_fn, vfntype); - } - else - { - release_fn = identifier_global_value (release_fn); - abort_fn = identifier_global_value (abort_fn); - } - - inner_if_stmt = begin_if_stmt (); - finish_if_stmt_cond (build_call (acquire_fn, guard_addr_list), - inner_if_stmt); - - inner_then_clause = begin_compound_stmt (BCS_NO_SCOPE); - begin = get_target_expr (boolean_false_node); - flag = TARGET_EXPR_SLOT (begin); - - TARGET_EXPR_CLEANUP (begin) - = build3 (COND_EXPR, void_type_node, flag, - void_zero_node, - build_call (abort_fn, guard_addr_list)); - CLEANUP_EH_ONLY (begin) = 1; - - /* Do the initialization itself. */ - init = add_stmt_to_compound (begin, init); - init = add_stmt_to_compound - (init, build2 (MODIFY_EXPR, void_type_node, flag, boolean_true_node)); - init = add_stmt_to_compound - (init, build_call (release_fn, guard_addr_list)); - } + /* Begin the conditional initialization. */ + if_stmt = begin_if_stmt (); + finish_if_stmt_cond (get_guard_cond (guard), if_stmt); + then_clause = begin_compound_stmt (/*has_no_scope=*/false); + + /* Do the initialization itself. */ + assignment = init ? init : NULL_TREE; + + /* Once the assignment is complete, set TEMP to 1. Since the + construction of the static object is complete at this point, + we want to make sure TEMP is set to 1 even if a temporary + constructed during the initialization throws an exception + when it is destroyed. So, we combine the initialization and + the assignment to TEMP into a single expression, ensuring + that when we call finish_expr_stmt the cleanups will not be + run until after TEMP is set to 1. */ + guard_init = set_guard (guard); + if (assignment) + assignment = build_compound_expr (assignment, guard_init); else - init = add_stmt_to_compound (init, set_guard (guard)); + assignment = guard_init; + finish_expr_stmt (assignment); /* Use atexit to register a function for destroying this static variable. */ - init = add_stmt_to_compound (init, register_dtor_fn (decl)); + register_dtor_fn (decl); - finish_expr_stmt (init); + finish_compound_stmt (then_clause); + finish_then_clause (if_stmt); + finish_if_stmt (); + } + else + static_aggregates = tree_cons (init, decl, static_aggregates); +} - if (flag_threadsafe_statics) - { - finish_compound_stmt (inner_then_clause); - finish_then_clause (inner_if_stmt); - finish_if_stmt (inner_if_stmt); - } +/* Finish the declaration of a catch-parameter. */ - if (!targetm.relaxed_ordering || !flag_threadsafe_statics) - { - finish_compound_stmt (then_clause); - finish_then_clause (if_stmt); - finish_if_stmt (if_stmt); - } +tree +start_handler_parms (tree declspecs, tree declarator) +{ + tree decl; + if (declspecs) + { + decl = grokdeclarator (declarator, declspecs, CATCHPARM, + 1, NULL); + if (decl == NULL_TREE) + error ("invalid catch parameter"); } else - static_aggregates = tree_cons (init, decl, static_aggregates); + decl = NULL_TREE; + + return decl; } /* Make TYPE a complete type based on INITIAL_VALUE. Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered, - 2 if there was no information (in which case assume 0 if DO_DEFAULT), - 3 if the initializer list is empty (in pedantic mode). */ + 2 if there was no information (in which case assume 0 if DO_DEFAULT). */ int -cp_complete_array_type (tree *ptype, tree initial_value, bool do_default) +complete_array_type (tree type, tree initial_value, int do_default) { - int failure; - tree type, elt_type; + tree maxindex = NULL_TREE; + int value = 0; if (initial_value) { /* An array of character type can be initialized from a - brace-enclosed string constant. - - FIXME: this code is duplicated from reshape_init. Probably - we should just call reshape_init here? */ - if (char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (*ptype))) + brace-enclosed string constant. */ + if (char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))) && TREE_CODE (initial_value) == CONSTRUCTOR - && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (initial_value))) + && CONSTRUCTOR_ELTS (initial_value) + && (TREE_CODE (TREE_VALUE (CONSTRUCTOR_ELTS (initial_value))) + == STRING_CST) + && TREE_CHAIN (CONSTRUCTOR_ELTS (initial_value)) == NULL_TREE) + initial_value = TREE_VALUE (CONSTRUCTOR_ELTS (initial_value)); + + /* Note MAXINDEX is really the maximum index, one less than the + size. */ + if (TREE_CODE (initial_value) == STRING_CST) { - VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (initial_value); - tree value = VEC_index (constructor_elt, v, 0)->value; + int eltsize + = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value))); + maxindex = build_int_2 ((TREE_STRING_LENGTH (initial_value) + / eltsize) - 1, 0); + } + else if (TREE_CODE (initial_value) == CONSTRUCTOR) + { + tree elts = CONSTRUCTOR_ELTS (initial_value); - if (TREE_CODE (value) == STRING_CST - && VEC_length (constructor_elt, v) == 1) - initial_value = value; + maxindex = ssize_int (-1); + for (; elts; elts = TREE_CHAIN (elts)) + { + if (TREE_PURPOSE (elts)) + maxindex = TREE_PURPOSE (elts); + else + maxindex = size_binop (PLUS_EXPR, maxindex, ssize_int (1)); + } + maxindex = copy_node (maxindex); + } + else + { + /* Make an error message unless that happened already. */ + if (initial_value != error_mark_node) + value = 1; + else + initial_value = NULL_TREE; + + /* Prevent further error messages. */ + maxindex = build_int_2 (0, 0); } } - failure = complete_array_type (ptype, initial_value, do_default); + if (!maxindex) + { + if (do_default) + maxindex = build_int_2 (0, 0); + value = 2; + } - /* We can create the array before the element type is complete, which - means that we didn't have these two bits set in the original type - either. In completing the type, we are expected to propagate these - bits. See also complete_type which does the same thing for arrays - of fixed size. */ - type = *ptype; - if (TYPE_DOMAIN (type)) + if (maxindex) { - elt_type = TREE_TYPE (type); - TYPE_NEEDS_CONSTRUCTING (type) = TYPE_NEEDS_CONSTRUCTING (elt_type); - TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) - = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (elt_type); + tree itype; + tree domain; + + domain = build_index_type (maxindex); + TYPE_DOMAIN (type) = domain; + + if (! TREE_TYPE (maxindex)) + TREE_TYPE (maxindex) = domain; + if (initial_value) + itype = TREE_TYPE (initial_value); + else + itype = NULL; + if (itype && !TYPE_DOMAIN (itype)) + TYPE_DOMAIN (itype) = domain; + /* The type of the main variant should never be used for arrays + of different sizes. It should only ever be completed with the + size of the array. */ + if (! TYPE_DOMAIN (TYPE_MAIN_VARIANT (type))) + TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)) = domain; } - return failure; + /* Lay out the type now that we can get the real answer. */ + + layout_type (type); + + return value; } /* Return zero if something is declared to be a member of type @@ -5854,9 +5522,11 @@ member_function_or_else (tree ctype, tree cur_type, enum overload_flags flags) if (ctype && ctype != cur_type) { if (flags == DTOR_FLAG) - error ("destructor for alien class %qT cannot be a member", ctype); + error ("destructor for alien class `%T' cannot be a member", + ctype); else - error ("constructor for alien class %qT cannot be a member", ctype); + error ("constructor for alien class `%T' cannot be a member", + ctype); return 0; } return 1; @@ -5869,86 +5539,28 @@ member_function_or_else (tree ctype, tree cur_type, enum overload_flags flags) static void bad_specifiers (tree object, - const char* type, - int virtualp, - int quals, - int inlinep, - int friendp, - int raises) + const char* type, + int virtualp, + int quals, + int inlinep, + int friendp, + int raises) { if (virtualp) - error ("%qD declared as a %<virtual%> %s", object, type); + error ("`%D' declared as a `virtual' %s", object, type); if (inlinep) - error ("%qD declared as an %<inline%> %s", object, type); + error ("`%D' declared as an `inline' %s", object, type); if (quals) - error ("%<const%> and %<volatile%> function specifiers on " - "%qD invalid in %s declaration", - object, type); + error ("`const' and `volatile' function specifiers on `%D' invalid in %s declaration", + object, type); if (friendp) - error ("%q+D declared as a friend", object); + cp_error_at ("`%D' declared as a friend", object); if (raises && (TREE_CODE (object) == TYPE_DECL || (!TYPE_PTRFN_P (TREE_TYPE (object)) && !TYPE_REFFN_P (TREE_TYPE (object)) && !TYPE_PTRMEMFUNC_P (TREE_TYPE (object))))) - error ("%q+D declared with an exception specification", object); -} - -/* DECL is a member function or static data member and is presently - being defined. Check that the definition is taking place in a - valid namespace. */ - -static void -check_class_member_definition_namespace (tree decl) -{ - /* These checks only apply to member functions and static data - members. */ - gcc_assert (TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == VAR_DECL); - /* We check for problems with specializations in pt.c in - check_specialization_namespace, where we can issue better - diagnostics. */ - if (processing_specialization) - return; - /* There are no restrictions on the placement of - explicit instantiations. */ - if (processing_explicit_instantiation) - return; - /* [class.mfct] - - A member function definition that appears outside of the - class definition shall appear in a namespace scope enclosing - the class definition. - - [class.static.data] - - The definition for a static data member shall appear in a - namespace scope enclosing the member's class definition. */ - if (!is_ancestor (current_namespace, DECL_CONTEXT (decl))) - pedwarn ("definition of %qD is not in namespace enclosing %qT", - decl, DECL_CONTEXT (decl)); -} - -/* Build a PARM_DECL for the "this" parameter. TYPE is the - METHOD_TYPE for a non-static member function; QUALS are the - cv-qualifiers that apply to the function. */ - -tree -build_this_parm (tree type, cp_cv_quals quals) -{ - tree this_type; - tree qual_type; - tree parm; - cp_cv_quals this_quals; - - this_type = TREE_VALUE (TYPE_ARG_TYPES (type)); - /* The `this' parameter is implicitly `const'; it cannot be - assigned to. */ - this_quals = (quals & TYPE_QUAL_RESTRICT) | TYPE_QUAL_CONST; - qual_type = cp_build_qualified_type (this_type, this_quals); - parm = build_artificial_parm (this_identifier, qual_type); - cp_apply_type_quals_to_decl (this_quals, parm); - return parm; + cp_error_at ("`%D' declared with an exception specification", object); } /* CTYPE is class type, or null if non-class. @@ -5964,112 +5576,41 @@ build_this_parm (tree type, cp_cv_quals quals) CHECK is 1 if we must find this method in CTYPE, 0 if we should not look, and -1 if we should not call `grokclassfn' at all. - SFK is the kind of special function (if any) for the new function. - Returns `NULL_TREE' if something goes wrong, after issuing applicable error messages. */ static tree -grokfndecl (tree ctype, - tree type, - tree declarator, +grokfndecl (tree ctype, + tree type, + tree declarator, tree parms, - tree orig_declarator, - int virtualp, - enum overload_flags flags, - cp_cv_quals quals, - tree raises, - int check, - int friendp, - int publicp, - int inlinep, - special_function_kind sfk, - bool funcdef_flag, - int template_count, - tree in_namespace, - tree* attrlist) + tree orig_declarator, + int virtualp, + enum overload_flags flags, + tree quals, + tree raises, + int check, + int friendp, + int publicp, + int inlinep, + int funcdef_flag, + int template_count, + tree in_namespace) { tree decl; int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE; + int has_default_arg = 0; tree t; if (raises) type = build_exception_variant (type, raises); decl = build_lang_decl (FUNCTION_DECL, declarator, type); - if (TREE_CODE (type) == METHOD_TYPE) - { - tree parm; - parm = build_this_parm (type, quals); - TREE_CHAIN (parm) = parms; - parms = parm; - } DECL_ARGUMENTS (decl) = parms; /* Propagate volatile out from type to decl. */ if (TYPE_VOLATILE (type)) TREE_THIS_VOLATILE (decl) = 1; - if (friendp - && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR) - { - if (funcdef_flag) - error - ("defining explicit specialization %qD in friend declaration", - orig_declarator); - else - { - tree fns = TREE_OPERAND (orig_declarator, 0); - tree args = TREE_OPERAND (orig_declarator, 1); - - if (PROCESSING_REAL_TEMPLATE_DECL_P ()) - { - /* Something like `template <class T> friend void f<T>()'. */ - error ("invalid use of template-id %qD in declaration " - "of primary template", - orig_declarator); - return NULL_TREE; - } - - - /* A friend declaration of the form friend void f<>(). Record - the information in the TEMPLATE_ID_EXPR. */ - SET_DECL_IMPLICIT_INSTANTIATION (decl); - - if (TREE_CODE (fns) == COMPONENT_REF) - { - /* Due to bison parser ickiness, we will have already looked - up an operator_name or PFUNCNAME within the current class - (see template_id in parse.y). If the current class contains - such a name, we'll get a COMPONENT_REF here. Undo that. */ - - gcc_assert (TREE_TYPE (TREE_OPERAND (fns, 0)) - == current_class_type); - fns = TREE_OPERAND (fns, 1); - } - gcc_assert (TREE_CODE (fns) == IDENTIFIER_NODE - || TREE_CODE (fns) == OVERLOAD); - DECL_TEMPLATE_INFO (decl) = tree_cons (fns, args, NULL_TREE); - - for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t)) - if (TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG) - { - error ("default arguments are not allowed in declaration " - "of friend template specialization %qD", - decl); - return NULL_TREE; - } - - if (inlinep) - { - error ("%<inline%> is not allowed in declaration of friend " - "template specialization %qD", - decl); - return NULL_TREE; - } - } - } - /* If this decl has namespace scope, set that up. */ if (in_namespace) set_decl_namespace (decl, in_namespace, friendp); @@ -6096,26 +5637,26 @@ grokfndecl (tree ctype, } if (ctype) - { - DECL_CONTEXT (decl) = ctype; - if (funcdef_flag) - check_class_member_definition_namespace (decl); - } + DECL_CONTEXT (decl) = ctype; if (ctype == NULL_TREE && DECL_MAIN_P (decl)) { if (processing_template_decl) - error ("cannot declare %<::main%> to be a template"); + error ("cannot declare `::main' to be a template"); if (inlinep) - error ("cannot declare %<::main%> to be inline"); + error ("cannot declare `::main' to be inline"); if (!publicp) - error ("cannot declare %<::main%> to be static"); + error ("cannot declare `::main' to be static"); + if (!same_type_p (TREE_TYPE (TREE_TYPE (decl)), + integer_type_node)) + error ("`main' must return `int'"); inlinep = 0; publicp = 1; } /* Members of anonymous types and local classes have no linkage; make - them internal. If a typedef is made later, this will be changed. */ + them internal. */ + /* FIXME what if it gets a name from typedef? */ if (ctype && (TYPE_ANONYMOUS_P (ctype) || decl_function_context (TYPE_MAIN_DECL (ctype)))) publicp = 0; @@ -6127,8 +5668,7 @@ grokfndecl (tree ctype, declare an entity with linkage. Only check this for public decls for now. See core 319, 389. */ - t = no_linkage_check (TREE_TYPE (decl), - /*relaxed_p=*/false); + t = no_linkage_check (TREE_TYPE (decl)); if (t) { if (TYPE_ANONYMOUS_P (t)) @@ -6137,16 +5677,17 @@ grokfndecl (tree ctype, /* Allow this; it's pretty common in C. */; else { - pedwarn ("non-local function %q#D uses anonymous type", + pedwarn ("non-local function `%#D' uses anonymous type", decl); if (DECL_ORIGINAL_TYPE (TYPE_NAME (t))) - pedwarn ("%q+#D does not refer to the unqualified " - "type, so it is not used for linkage", - TYPE_NAME (t)); + cp_pedwarn_at ("\ +`%#D' does not refer to the unqualified type, so it is not used for linkage", + TYPE_NAME (t)); } } else - pedwarn ("non-local function %q#D uses local type %qT", decl, t); + pedwarn ("non-local function `%#D' uses local type `%T'", + decl, t); } } @@ -6167,20 +5708,83 @@ grokfndecl (tree ctype, DECL_INLINE (decl) = 1; DECL_EXTERNAL (decl) = 1; - if (quals && TREE_CODE (type) == FUNCTION_TYPE) + if (quals != NULL_TREE && TREE_CODE (type) == FUNCTION_TYPE) { - error ("%smember function %qD cannot have cv-qualifier", - (ctype ? "static " : "non-"), decl); - quals = TYPE_UNQUALIFIED; + error ("%smember function `%D' cannot have `%T' method qualifier", + (ctype ? "static " : "non-"), decl, TREE_VALUE (quals)); + quals = NULL_TREE; } - if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)) - && !grok_op_properties (decl, /*complain=*/true)) - return NULL_TREE; + if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))) + grok_op_properties (decl, /*complain=*/true); if (ctype && decl_function_context (decl)) DECL_NO_STATIC_CHAIN (decl) = 1; + for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t)) + if (TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG) + { + has_default_arg = 1; + break; + } + + if (friendp + && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR) + { + if (funcdef_flag) + error + ("defining explicit specialization `%D' in friend declaration", + orig_declarator); + else + { + tree fns = TREE_OPERAND (orig_declarator, 0); + tree args = TREE_OPERAND (orig_declarator, 1); + + if (PROCESSING_REAL_TEMPLATE_DECL_P ()) + { + /* Something like `template <class T> friend void f<T>()'. */ + error ("invalid use of template-id `%D' in declaration of primary template", + orig_declarator); + return NULL_TREE; + } + + + /* A friend declaration of the form friend void f<>(). Record + the information in the TEMPLATE_ID_EXPR. */ + SET_DECL_IMPLICIT_INSTANTIATION (decl); + + if (TREE_CODE (fns) == COMPONENT_REF) + { + /* Due to bison parser ickiness, we will have already looked + up an operator_name or PFUNCNAME within the current class + (see template_id in parse.y). If the current class contains + such a name, we'll get a COMPONENT_REF here. Undo that. */ + + my_friendly_assert (TREE_TYPE (TREE_OPERAND (fns, 0)) + == current_class_type, 20001120); + fns = TREE_OPERAND (fns, 1); + } + my_friendly_assert (TREE_CODE (fns) == IDENTIFIER_NODE + || TREE_CODE (fns) == OVERLOAD, 20001120); + DECL_TEMPLATE_INFO (decl) = tree_cons (fns, args, NULL_TREE); + + if (has_default_arg) + { + error ("default arguments are not allowed in declaration of friend template specialization `%D'", + decl); + return NULL_TREE; + } + + if (inlinep) + { + error ("`inline' is not allowed in declaration of friend template specialization `%D'", + decl); + return NULL_TREE; + } + } + } + if (funcdef_flag) /* Make the init_value nonzero so pushdecl knows this is not tentative. error_mark_node is replaced later with the BLOCK. */ @@ -6193,39 +5797,22 @@ grokfndecl (tree ctype, if (check < 0) return decl; - if (ctype != NULL_TREE) - { - if (sfk == sfk_constructor) - DECL_CONSTRUCTOR_P (decl) = 1; + if (flags == NO_SPECIAL && ctype && constructor_name_p (declarator, ctype)) + DECL_CONSTRUCTOR_P (decl) = 1; - grokclassfn (ctype, decl, flags); - } + /* Function gets the ugly name, field gets the nice one. This call + may change the type of the function (because of default + parameters)! */ + if (ctype != NULL_TREE) + grokclassfn (ctype, decl, flags, quals); decl = check_explicit_specialization (orig_declarator, decl, template_count, - 2 * funcdef_flag + + 2 * (funcdef_flag != 0) + 4 * (friendp != 0)); if (decl == error_mark_node) return NULL_TREE; - if (attrlist) - { - cplus_decl_attributes (&decl, *attrlist, 0); - *attrlist = NULL_TREE; - } - - /* Check main's type after attributes have been applied. */ - if (ctype == NULL_TREE && DECL_MAIN_P (decl) - && !same_type_p (TREE_TYPE (TREE_TYPE (decl)), - integer_type_node)) - { - tree oldtypeargs = TYPE_ARG_TYPES (TREE_TYPE (decl)); - tree newtype; - error ("%<::main%> must return %<int%>"); - newtype = build_function_type (integer_type_node, oldtypeargs); - TREE_TYPE (decl) = newtype; - } - if (ctype != NULL_TREE && (! TYPE_FOR_JAVA (ctype) || check_java_method (decl)) && check) @@ -6233,29 +5820,28 @@ grokfndecl (tree ctype, tree old_decl; old_decl = check_classfn (ctype, decl, - (processing_template_decl - > template_class_depth (ctype)) - ? current_template_parms - : NULL_TREE); + processing_template_decl + > template_class_depth (ctype)); + + if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL) + /* Because grokfndecl is always supposed to return a + FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT + here. We depend on our callers to figure out that its + really a template that's being returned. */ + old_decl = DECL_TEMPLATE_RESULT (old_decl); + + if (old_decl && DECL_STATIC_FUNCTION_P (old_decl) + && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) + /* Remove the `this' parm added by grokclassfn. + XXX Isn't this done in start_function, too? */ + revert_static_member_fn (decl); + if (old_decl && DECL_ARTIFICIAL (old_decl)) + error ("definition of implicitly-declared `%D'", old_decl); + if (old_decl) { tree ok; - tree pushed_scope; - - if (TREE_CODE (old_decl) == TEMPLATE_DECL) - /* Because grokfndecl is always supposed to return a - FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT - here. We depend on our callers to figure out that its - really a template that's being returned. */ - old_decl = DECL_TEMPLATE_RESULT (old_decl); - - if (DECL_STATIC_FUNCTION_P (old_decl) - && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) - /* Remove the `this' parm added by grokclassfn. - XXX Isn't this done in start_function, too? */ - revert_static_member_fn (decl); - if (DECL_ARTIFICIAL (old_decl)) - error ("definition of implicitly-declared %qD", old_decl); + bool pop_p; /* Since we've smashed OLD_DECL to its DECL_TEMPLATE_RESULT, we must do the same to DECL. */ @@ -6264,13 +5850,13 @@ grokfndecl (tree ctype, /* Attempt to merge the declarations. This can fail, in the case of some invalid specialization declarations. */ - pushed_scope = push_scope (ctype); - ok = duplicate_decls (decl, old_decl, friendp); - if (pushed_scope) - pop_scope (pushed_scope); + pop_p = push_scope (ctype); + ok = duplicate_decls (decl, old_decl); + if (pop_p) + pop_scope (ctype); if (!ok) { - error ("no %q#D member function declared in class %qT", + error ("no `%#D' member function declared in class `%T'", decl, ctype); return NULL_TREE; } @@ -6290,26 +5876,7 @@ grokfndecl (tree ctype, return decl; } -/* DECL is a VAR_DECL for a static data member. Set flags to reflect - the linkage that DECL will receive in the object file. */ - -static void -set_linkage_for_static_data_member (tree decl) -{ - /* A static data member always has static storage duration and - external linkage. Note that static data members are forbidden in - local classes -- the only situation in which a class has - non-external linkage. */ - TREE_PUBLIC (decl) = 1; - TREE_STATIC (decl) = 1; - /* For non-template classes, static data members are always put - out in exactly those files where they are defined, just as - with ordinary namespace-scope variables. */ - if (!processing_template_decl) - DECL_INTERFACE_KNOWN (decl) = 1; -} - -/* Create a VAR_DECL named NAME with the indicated TYPE. +/* Create a VAR_DECL named NAME with the indicated TYPE. If SCOPE is non-NULL, it is the class type or namespace containing the variable. If SCOPE is NULL, the variable should is created in @@ -6317,28 +5884,36 @@ set_linkage_for_static_data_member (tree decl) static tree grokvardecl (tree type, - tree name, - const cp_decl_specifier_seq *declspecs, - int initialized, - int constp, - tree scope) + tree name, + RID_BIT_TYPE * specbits_in, + int initialized, + int constp, + tree scope) { tree decl; tree explicit_scope; + RID_BIT_TYPE specbits; - gcc_assert (!name || TREE_CODE (name) == IDENTIFIER_NODE); + my_friendly_assert (!name || TREE_CODE (name) == IDENTIFIER_NODE, + 20020808); + + specbits = *specbits_in; /* Compute the scope in which to place the variable, but remember - whether or not that scope was explicitly specified by the user. */ + whether or not that scope was explicitly specified by the user. */ explicit_scope = scope; if (!scope) { /* An explicit "extern" specifier indicates a namespace-scope variable. */ - if (declspecs->storage_class == sc_extern) + if (RIDBIT_SETP (RID_EXTERN, specbits)) scope = current_namespace; else if (!at_function_scope_p ()) - scope = current_scope (); + { + scope = current_scope (); + if (!scope) + scope = current_namespace; + } } if (scope @@ -6347,7 +5922,7 @@ grokvardecl (tree type, (TREE_CODE (scope) == NAMESPACE_DECL && processing_template_decl) /* Similarly for namespace-scope variables with language linkage other than C++. */ - || (TREE_CODE (scope) == NAMESPACE_DECL + || (TREE_CODE (scope) == NAMESPACE_DECL && current_lang_name != lang_name_cplusplus) /* Similarly for static data members. */ || TYPE_P (scope))) @@ -6358,40 +5933,47 @@ grokvardecl (tree type, if (explicit_scope && TREE_CODE (explicit_scope) == NAMESPACE_DECL) set_decl_namespace (decl, explicit_scope, 0); else - DECL_CONTEXT (decl) = FROB_CONTEXT (scope); + DECL_CONTEXT (decl) = scope; + + if (name && scope && current_lang_name != lang_name_c) + /* We can't mangle lazily here because we don't have any + way to recover whether or not a variable was `extern + "C"' later. */ + mangle_decl (decl); - if (declspecs->storage_class == sc_extern) + if (RIDBIT_SETP (RID_EXTERN, specbits)) { DECL_THIS_EXTERN (decl) = 1; DECL_EXTERNAL (decl) = !initialized; } + /* In class context, static means one per class, + public access, and static storage. */ if (DECL_CLASS_SCOPE_P (decl)) { - set_linkage_for_static_data_member (decl); - /* This function is only called with out-of-class definitions. */ + TREE_PUBLIC (decl) = 1; + TREE_STATIC (decl) = 1; DECL_EXTERNAL (decl) = 0; - check_class_member_definition_namespace (decl); } /* At top level, either `static' or no s.c. makes a definition (perhaps tentative), and absence of `static' makes it public. */ else if (toplevel_bindings_p ()) { - TREE_PUBLIC (decl) = (declspecs->storage_class != sc_static + TREE_PUBLIC (decl) = (RIDBIT_NOTSETP (RID_STATIC, specbits) && (DECL_THIS_EXTERN (decl) || ! constp)); TREE_STATIC (decl) = ! DECL_EXTERNAL (decl); } /* Not at top level, only `static' makes a static definition. */ else { - TREE_STATIC (decl) = declspecs->storage_class == sc_static; + TREE_STATIC (decl) = !! RIDBIT_SETP (RID_STATIC, specbits); TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); } - if (declspecs->specs[(int)ds_thread]) + if (RIDBIT_SETP (RID_THREAD, specbits)) { if (targetm.have_tls) - DECL_TLS_MODEL (decl) = decl_default_tls_model (decl); + DECL_THREAD_LOCAL (decl) = 1; else /* A mere warning is sure to result in improper semantics at runtime. Don't bother to allow this to compile. */ @@ -6405,34 +5987,16 @@ grokvardecl (tree type, declare an entity with linkage. Only check this for public decls for now. */ - tree t = no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false); + tree t = no_linkage_check (TREE_TYPE (decl)); if (t) { if (TYPE_ANONYMOUS_P (t)) - { - if (DECL_EXTERN_C_P (decl)) - /* Allow this; it's pretty common in C. */ - ; - else - { - /* DRs 132, 319 and 389 seem to indicate types with - no linkage can only be used to declare extern "C" - entities. Since it's not always an error in the - ISO C++ 90 Standard, we only issue a warning. */ - warning (0, "non-local variable %q#D uses anonymous type", - decl); - if (DECL_ORIGINAL_TYPE (TYPE_NAME (t))) - warning (0, "%q+#D does not refer to the unqualified " - "type, so it is not used for linkage", - TYPE_NAME (t)); - } - } + /* Ignore for now; `enum { foo } e' is pretty common. */; else - warning (0, "non-local variable %q#D uses local type %qT", decl, t); + pedwarn ("non-local variable `%#D' uses local type `%T'", + decl, t); } } - else - DECL_INTERFACE_KNOWN (decl) = 1; return decl; } @@ -6464,8 +6028,6 @@ build_ptrmemfunc_type (tree type) = build_ptrmemfunc_type (TYPE_MAIN_VARIANT (type)); t = make_aggr_type (RECORD_TYPE); - xref_basetypes (t, NULL_TREE); - /* Let the front-end know this is a pointer to member function... */ TYPE_PTRMEMFUNC_FLAG (t) = 1; /* ... and not really an aggregate. */ @@ -6473,11 +6035,11 @@ build_ptrmemfunc_type (tree type) field = build_decl (FIELD_DECL, pfn_identifier, type); fields = field; - + field = build_decl (FIELD_DECL, delta_identifier, delta_type_node); TREE_CHAIN (field) = fields; fields = field; - + finish_builtin_struct (t, "__ptrmemfunc_type", fields, ptr_type_node); /* Zap out the name so that the back-end will give us the debugging @@ -6513,18 +6075,19 @@ build_ptrmem_type (tree class_type, tree member_type) tree arg_types; arg_types = TYPE_ARG_TYPES (member_type); - class_type = (cp_build_qualified_type + class_type = (cp_build_qualified_type (class_type, cp_type_quals (TREE_TYPE (TREE_VALUE (arg_types))))); - member_type - = build_method_type_directly (class_type, + member_type + = build_method_type_directly (class_type, TREE_TYPE (member_type), TREE_CHAIN (arg_types)); return build_ptrmemfunc_type (build_pointer_type (member_type)); } else { - gcc_assert (TREE_CODE (member_type) != FUNCTION_TYPE); + my_friendly_assert (TREE_CODE (member_type) != FUNCTION_TYPE, + 20030716); return build_offset_type (class_type, member_type); } } @@ -6545,22 +6108,19 @@ check_static_variable_definition (tree decl, tree type) required. */ if (!ARITHMETIC_TYPE_P (type) && TREE_CODE (type) != ENUMERAL_TYPE) { - error ("invalid in-class initialization of static data member " - "of non-integral type %qT", + error ("invalid in-class initialization of static data member of non-integral type `%T'", type); /* If we just return the declaration, crashes will sometimes - occur. We therefore return void_type_node, as if this were a + occur. We therefore return void_type_node, as if this was a friend declaration, to cause callers to completely ignore this declaration. */ return 1; } else if (!CP_TYPE_CONST_P (type)) - error ("ISO C++ forbids in-class initialization of non-const " - "static member %qD", - decl); + error ("ISO C++ forbids in-class initialization of non-const static member `%D'", + decl); else if (pedantic && !INTEGRAL_TYPE_P (type)) - pedwarn ("ISO C++ forbids initialization of member constant " - "%qD of non-integral type %qT", decl, type); + pedwarn ("ISO C++ forbids initialization of member constant `%D' of non-integral type `%T'", decl, type); return 0; } @@ -6572,20 +6132,16 @@ check_static_variable_definition (tree decl, tree type) tree compute_array_index_type (tree name, tree size) { - tree type; + tree type = TREE_TYPE (size); tree itype; - if (error_operand_p (size)) - return error_mark_node; - - type = TREE_TYPE (size); /* The array bound must be an integer type. */ if (!dependent_type_p (type) && !INTEGRAL_TYPE_P (type)) { if (name) - error ("size of array %qD has non-integral type %qT", name, type); + error ("size of array `%D' has non-integral type `%T'", name, type); else - error ("size of array has non-integral type %qT", type); + error ("size of array has non-integral type `%T'", type); size = integer_one_node; type = TREE_TYPE (size); } @@ -6603,7 +6159,7 @@ compute_array_index_type (tree name, tree size) STRIP_TYPE_NOPS (size); /* It might be a const variable or enumeration constant. */ - size = integral_constant_value (size); + size = decl_constant_value (size); /* Normally, the array-bound will be a constant. */ if (TREE_CODE (size) == INTEGER_CST) @@ -6621,7 +6177,7 @@ compute_array_index_type (tree name, tree size) if (INT_CST_LT (size, integer_zero_node)) { if (name) - error ("size of array %qD is negative", name); + error ("size of array `%D' is negative", name); else error ("size of array is negative"); size = integer_one_node; @@ -6631,7 +6187,7 @@ compute_array_index_type (tree name, tree size) else if (integer_zerop (size) && pedantic && !in_system_header) { if (name) - pedwarn ("ISO C++ forbids zero-size array %qD", name); + pedwarn ("ISO C++ forbids zero-size array `%D'", name); else pedwarn ("ISO C++ forbids zero-size array"); } @@ -6640,16 +6196,15 @@ compute_array_index_type (tree name, tree size) { /* `(int) &fn' is not a valid array bound. */ if (name) - error ("size of array %qD is not an integral constant-expression", - name); + error ("size of array `%D' is not an integral constant-expression", + name); else error ("size of array is not an integral constant-expression"); - size = integer_one_node; } else if (pedantic) { if (name) - pedwarn ("ISO C++ forbids variable-size array %qD", name); + pedwarn ("ISO C++ forbids variable-size array `%D'", name); else pedwarn ("ISO C++ forbids variable-size array"); } @@ -6659,28 +6214,19 @@ compute_array_index_type (tree name, tree size) itype = build_min (MINUS_EXPR, sizetype, size, integer_one_node); else { - HOST_WIDE_INT saved_processing_template_decl; - /* Compute the index of the largest element in the array. It is - one less than the number of elements in the array. We save - and restore PROCESSING_TEMPLATE_DECL so that computations in - cp_build_binary_op will be appropriately folded. */ - saved_processing_template_decl = processing_template_decl; - processing_template_decl = 0; - itype = cp_build_binary_op (MINUS_EXPR, - cp_convert (ssizetype, size), - cp_convert (ssizetype, integer_one_node)); - itype = fold (itype); - processing_template_decl = saved_processing_template_decl; - + one less than the number of elements in the array. */ + itype + = fold (cp_build_binary_op (MINUS_EXPR, + cp_convert (ssizetype, size), + cp_convert (ssizetype, integer_one_node))); if (!TREE_CONSTANT (itype)) /* A variable sized array. */ itype = variable_size (itype); /* Make sure that there was no overflow when creating to a signed - index type. (For example, on a 32-bit machine, an array with - size 2^32 - 1 is too big.) */ - else if (TREE_CODE (itype) == INTEGER_CST - && TREE_OVERFLOW (itype)) + index type. (For example, on a 32-bit machine, an array with + size 2^32 - 1 is too big.) */ + else if (TREE_OVERFLOW (itype)) { error ("overflow in array dimension"); TREE_OVERFLOW (itype) = 0; @@ -6696,20 +6242,40 @@ compute_array_index_type (tree name, tree size) unqualified name, NULL_TREE is returned. */ tree -get_scope_of_declarator (const cp_declarator *declarator) +get_scope_of_declarator (tree declarator) { - while (declarator && declarator->kind != cdk_id) - declarator = declarator->declarator; - - /* If the declarator-id is a SCOPE_REF, the scope in which the - declaration occurs is the first operand. */ - if (declarator - && declarator->u.id.qualifying_scope) - return declarator->u.id.qualifying_scope; - - /* Otherwise, the declarator is not a qualified name; the entity will - be declared in the current scope. */ - return NULL_TREE; + if (!declarator) + return NULL_TREE; + + switch (TREE_CODE (declarator)) + { + case CALL_EXPR: + case ARRAY_REF: + case INDIRECT_REF: + case ADDR_EXPR: + /* For any of these, the main declarator is the first operand. */ + return get_scope_of_declarator (TREE_OPERAND + (declarator, 0)); + + case SCOPE_REF: + /* For a pointer-to-member, continue descending. */ + if (TREE_CODE (TREE_OPERAND (declarator, 1)) + == INDIRECT_REF) + return get_scope_of_declarator (TREE_OPERAND + (declarator, 1)); + /* Otherwise, if the declarator-id is a SCOPE_REF, the scope in + which the declaration occurs is the first operand. */ + return TREE_OPERAND (declarator, 0); + + case TREE_LIST: + /* Attributes to be applied. The declarator is TREE_VALUE. */ + return get_scope_of_declarator (TREE_VALUE (declarator)); + + default: + /* Otherwise, we have a declarator-id which is not a qualified + name; the entity will be declared in the current scope. */ + return NULL_TREE; + } } /* Returns an ARRAY_TYPE for an array with SIZE elements of the @@ -6756,7 +6322,7 @@ create_array_type_for_decl (tree name, tree type, tree size) if (error_msg) { if (name) - error ("declaration of %qD as %s", name, error_msg); + error ("declaration of `%D' as %s", name, error_msg); else error ("creating %s", error_msg); @@ -6770,12 +6336,10 @@ create_array_type_for_decl (tree name, tree type, tree size) if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type)) { if (name) - error ("declaration of %qD as multidimensional array must " - "have bounds for all dimensions except the first", - name); + error ("declaration of `%D' as multidimensional array must have bounds for all dimensions except the first", + name); else - error ("multidimensional array must have bounds for all " - "dimensions except the first"); + error ("multidimensional array must have bounds for all dimensions except the first"); return error_mark_node; } @@ -6784,26 +6348,20 @@ create_array_type_for_decl (tree name, tree type, tree size) if (size) itype = compute_array_index_type (name, size); - /* [dcl.array] - T is called the array element type; this type shall not be [...] an - abstract class type. */ - abstract_virtuals_error (name, type); - return build_cplus_array_type (type, itype); } /* Check that it's OK to declare a function with the indicated TYPE. SFK indicates the kind of special function (if any) that this function is. OPTYPE is the type given in a conversion operator - declaration, or the class type for a constructor/destructor. - Returns the actual return type of the function; that + declaration. Returns the actual return type of the function; that may be different than TYPE if an error occurs, or for certain special functions. */ static tree check_special_function_return_type (special_function_kind sfk, - tree type, - tree optype) + tree type, + tree optype) { switch (sfk) { @@ -6811,35 +6369,26 @@ check_special_function_return_type (special_function_kind sfk, if (type) error ("return type specification for constructor invalid"); - if (targetm.cxx.cdtor_returns_this () && !TYPE_FOR_JAVA (optype)) - type = build_pointer_type (optype); - else - type = void_type_node; + type = void_type_node; break; case sfk_destructor: if (type) error ("return type specification for destructor invalid"); - /* We can't use the proper return type here because we run into - problems with ambiguous bases and covariant returns. - Java classes are left unchanged because (void *) isn't a valid - Java type, and we don't want to change the Java ABI. */ - if (targetm.cxx.cdtor_returns_this () && !TYPE_FOR_JAVA (optype)) - type = build_pointer_type (void_type_node); - else - type = void_type_node; + type = void_type_node; break; case sfk_conversion: if (type && !same_type_p (type, optype)) - error ("operator %qT declared to return %qT", optype, type); + error ("operator `%T' declared to return `%T'", optype, type); else if (type) - pedwarn ("return type specified for %<operator %T%>", optype); + pedwarn ("return type specified for `operator %T'", optype); type = optype; break; default: - gcc_unreachable (); + abort (); + break; } return type; @@ -6848,7 +6397,7 @@ check_special_function_return_type (special_function_kind sfk, /* A variable or data member (whose unqualified name is IDENTIFIER) has been declared with the indicated TYPE. If the TYPE is not acceptable, issue an error message and return a type to use for - error-recovery purposes. */ + error-recovery purposes. */ tree check_var_type (tree identifier, tree type) @@ -6859,14 +6408,15 @@ check_var_type (tree identifier, tree type) error ("unnamed variable or field declared void"); else if (TREE_CODE (identifier) == IDENTIFIER_NODE) { - gcc_assert (!IDENTIFIER_OPNAME_P (identifier)); - error ("variable or field %qE declared void", identifier); + if (IDENTIFIER_OPNAME_P (identifier)) + abort (); + error ("variable or field `%E' declared void", identifier); } else error ("variable or field declared void"); - type = error_mark_node; + type = integer_type_node; } - + return type; } @@ -6907,33 +6457,33 @@ check_var_type (tree identifier, tree type) void S::f() { ... } when grokdeclarator is called for `S::f', the CURRENT_CLASS_TYPE - should not be `S'. - - Returns a DECL (if a declarator is present), a TYPE (if there is no - declarator, in cases like "struct S;"), or the ERROR_MARK_NODE if an - error occurs. */ + should not be `S'. */ tree -grokdeclarator (const cp_declarator *declarator, - const cp_decl_specifier_seq *declspecs, - enum decl_context decl_context, - int initialized, - tree* attrlist) -{ +grokdeclarator (tree declarator, + tree declspecs, + enum decl_context decl_context, + int initialized, + tree* attrlist) +{ + RID_BIT_TYPE specbits; + int nclasses = 0; + tree spec; tree type = NULL_TREE; int longlong = 0; + int type_quals; int virtualp, explicitp, friendp, inlinep, staticp; int explicit_int = 0; int explicit_char = 0; int defaulted_int = 0; - tree dependent_name = NULL_TREE; - + int extern_langp = 0; + tree dependant_name = NULL_TREE; + tree typedef_decl = NULL_TREE; - const char *name = NULL; + const char *name; tree typedef_type = NULL_TREE; - /* True if this declarator is a function definition. */ - bool funcdef_flag = false; - cp_declarator_kind innermost_code = cdk_error; + int funcdef_flag = 0; + enum tree_code innermost_code = ERROR_MARK; int bitfield = 0; #if 0 /* See the code below that used this. */ @@ -6946,214 +6496,307 @@ grokdeclarator (const cp_declarator *declarator, special_function_kind sfk = sfk_none; tree dname = NULL_TREE; + tree ctype = current_class_type; tree ctor_return_type = NULL_TREE; enum overload_flags flags = NO_SPECIAL; - /* cv-qualifiers that apply to the declarator, for a declaration of - a member function. */ - cp_cv_quals memfn_quals = TYPE_UNQUALIFIED; - /* cv-qualifiers that apply to the type specified by the DECLSPECS. */ - int type_quals; + tree quals = NULL_TREE; tree raises = NULL_TREE; int template_count = 0; + tree in_namespace = NULL_TREE; tree returned_attrs = NULL_TREE; + tree scope = NULL_TREE; tree parms = NULL_TREE; - const cp_declarator *id_declarator; - /* The unqualified name of the declarator; either an - IDENTIFIER_NODE, BIT_NOT_EXPR, or TEMPLATE_ID_EXPR. */ - tree unqualified_id; - /* The class type, if any, in which this entity is located, - or NULL_TREE if none. Note that this value may be different from - the current class type; for example if an attempt is made to declare - "A::f" inside "B", this value will be "A". */ - tree ctype = current_class_type; - /* The NAMESPACE_DECL for the namespace in which this entity is - located. If an unqualified name is used to declare the entity, - this value will be NULL_TREE, even if the entity is located at - namespace scope. */ - tree in_namespace = NULL_TREE; - cp_storage_class storage_class; - bool unsigned_p, signed_p, short_p, long_p, thread_p; - bool type_was_error_mark_node = false; - - signed_p = declspecs->specs[(int)ds_signed]; - unsigned_p = declspecs->specs[(int)ds_unsigned]; - short_p = declspecs->specs[(int)ds_short]; - long_p = declspecs->specs[(int)ds_long]; - longlong = declspecs->specs[(int)ds_long] >= 2; - thread_p = declspecs->specs[(int)ds_thread]; + RIDBIT_RESET_ALL (specbits); if (decl_context == FUNCDEF) - funcdef_flag = true, decl_context = NORMAL; + funcdef_flag = 1, decl_context = NORMAL; else if (decl_context == MEMFUNCDEF) - funcdef_flag = true, decl_context = FIELD; + funcdef_flag = -1, decl_context = FIELD; else if (decl_context == BITFIELD) bitfield = 1, decl_context = FIELD; /* Look inside a declarator for the name being declared and get it as a string, for an error message. */ - for (id_declarator = declarator; - id_declarator; - id_declarator = id_declarator->declarator) - { - if (id_declarator->kind != cdk_id) - innermost_code = id_declarator->kind; + { + tree *next = &declarator; + tree decl; + name = NULL; - switch (id_declarator->kind) - { - case cdk_function: - if (id_declarator->declarator - && id_declarator->declarator->kind == cdk_id) + while (next && *next) + { + decl = *next; + switch (TREE_CODE (decl)) + { + case TREE_LIST: + /* For attributes. */ + next = &TREE_VALUE (decl); + break; + + case COND_EXPR: + ctype = NULL_TREE; + next = &TREE_OPERAND (decl, 0); + break; + + case BIT_NOT_EXPR: /* For C++ destructors! */ { - sfk = id_declarator->declarator->u.id.sfk; - if (sfk == sfk_destructor) - flags = DTOR_FLAG; + tree name = TREE_OPERAND (decl, 0); + tree rename = NULL_TREE; + + my_friendly_assert (flags == NO_SPECIAL, 152); + flags = DTOR_FLAG; + sfk = sfk_destructor; + if (TYPE_P (name)) + TREE_OPERAND (decl, 0) = name = constructor_name (name); + my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153); + if (ctype == NULL_TREE) + { + if (current_class_type == NULL_TREE) + { + error ("destructors must be member functions"); + flags = NO_SPECIAL; + } + else + { + tree t = constructor_name (current_class_type); + if (t != name) + rename = t; + } + } + else + { + tree t = constructor_name (ctype); + if (t != name) + rename = t; + } + + if (rename) + { + error ("destructor `%T' must match class name `%T'", + name, rename); + TREE_OPERAND (decl, 0) = rename; + } + next = &name; } - break; + break; - case cdk_id: - { - tree qualifying_scope = id_declarator->u.id.qualifying_scope; - tree decl = id_declarator->u.id.unqualified_name; - if (!decl) - break; - if (qualifying_scope) + case ADDR_EXPR: /* C++ reference declaration */ + /* Fall through. */ + case ARRAY_REF: + case INDIRECT_REF: + ctype = NULL_TREE; + innermost_code = TREE_CODE (decl); + next = &TREE_OPERAND (decl, 0); + break; + + case CALL_EXPR: + innermost_code = TREE_CODE (decl); + if (decl_context == FIELD && ctype == NULL_TREE) + ctype = current_class_type; + if (ctype + && TREE_OPERAND (decl, 0) + && (TREE_CODE (TREE_OPERAND (decl, 0)) == TYPE_DECL + && constructor_name_p (DECL_NAME (TREE_OPERAND (decl, 0)), + ctype))) + TREE_OPERAND (decl, 0) = constructor_name (ctype); + next = &TREE_OPERAND (decl, 0); + decl = *next; + if (ctype != NULL_TREE + && decl != NULL_TREE && flags != DTOR_FLAG + && constructor_name_p (decl, ctype)) { - if (at_function_scope_p ()) - { - /* [dcl.meaning] - - A declarator-id shall not be qualified except - for ... - - None of the cases are permitted in block - scope. */ - if (qualifying_scope == global_namespace) - error ("invalid use of qualified-name %<::%D%>", - decl); - else if (TYPE_P (qualifying_scope)) - error ("invalid use of qualified-name %<%T::%D%>", - qualifying_scope, decl); - else - error ("invalid use of qualified-name %<%D::%D%>", - qualifying_scope, decl); - return error_mark_node; - } - else if (TYPE_P (qualifying_scope)) + sfk = sfk_constructor; + ctor_return_type = ctype; + } + ctype = NULL_TREE; + break; + + case TEMPLATE_ID_EXPR: + { + tree fns = TREE_OPERAND (decl, 0); + + dname = fns; + if (TREE_CODE (dname) == COMPONENT_REF) + dname = TREE_OPERAND (dname, 1); + if (TREE_CODE (dname) != IDENTIFIER_NODE) { - ctype = qualifying_scope; - if (innermost_code != cdk_function - && current_class_type - && !UNIQUELY_DERIVED_FROM_P (ctype, - current_class_type)) - { - error ("type %qT is not derived from type %qT", - ctype, current_class_type); - return error_mark_node; - } + my_friendly_assert (is_overloaded_fn (dname), + 19990331); + dname = DECL_NAME (get_first_fn (dname)); } - else if (TREE_CODE (qualifying_scope) == NAMESPACE_DECL) - in_namespace = qualifying_scope; } - switch (TREE_CODE (decl)) + /* Fall through. */ + + case IDENTIFIER_NODE: + if (TREE_CODE (decl) == IDENTIFIER_NODE) + dname = decl; + + next = 0; + + if (C_IS_RESERVED_WORD (dname)) { - case BIT_NOT_EXPR: - { - tree type; + error ("declarator-id missing; using reserved word `%D'", + dname); + name = IDENTIFIER_POINTER (dname); + } + else if (!IDENTIFIER_TYPENAME_P (dname)) + name = IDENTIFIER_POINTER (dname); + else + { + my_friendly_assert (flags == NO_SPECIAL, 154); + flags = TYPENAME_FLAG; + ctor_return_type = TREE_TYPE (dname); + sfk = sfk_conversion; + if (is_typename_at_global_scope (dname)) + name = IDENTIFIER_POINTER (dname); + else + name = "<invalid operator>"; + } + break; - if (innermost_code != cdk_function) - { - error ("declaration of %qD as non-function", decl); - return error_mark_node; - } - else if (!qualifying_scope - && !(current_class_type && at_class_scope_p ())) + /* C++ extension */ + case SCOPE_REF: + { + /* Perform error checking, and decide on a ctype. */ + tree cname = TREE_OPERAND (decl, 0); + if (cname == NULL_TREE) + ctype = NULL_TREE; + else if (TREE_CODE (cname) == NAMESPACE_DECL) + { + ctype = NULL_TREE; + in_namespace = TREE_OPERAND (decl, 0); + } + else if (! is_aggr_type (cname, 1)) + ctype = NULL_TREE; + /* Must test TREE_OPERAND (decl, 1), in case user gives + us `typedef (class::memfunc)(int); memfunc *memfuncptr;' */ + else if (TREE_OPERAND (decl, 1) + && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF) + ctype = cname; + else if (TREE_CODE (cname) == TEMPLATE_TYPE_PARM + || TREE_CODE (cname) == BOUND_TEMPLATE_TEMPLATE_PARM) + { + /* This might be declaring a member of a template + parm to be a friend. */ + ctype = cname; + dependant_name = TREE_OPERAND (decl, 1); + } + else if (ctype == NULL_TREE) + ctype = cname; + else if (TREE_COMPLEXITY (decl) == current_class_depth) + ; + else + { + if (! UNIQUELY_DERIVED_FROM_P (cname, ctype)) { - error ("declaration of %qD as non-member", decl); - return error_mark_node; + error ("type `%T' is not derived from type `%T'", + cname, ctype); + ctype = NULL_TREE; } - - type = TREE_OPERAND (decl, 0); - name = IDENTIFIER_POINTER (constructor_name (type)); - dname = decl; + else + ctype = cname; } - break; - case TEMPLATE_ID_EXPR: + /* It is valid to write: + + class C { void f(); }; + typedef C D; + void D::f(); + + The standard is not clear about whether `typedef const C D' is + legal; as of 2002-09-15 the committee is considering + that question. EDG 3.0 allows that syntax. + Therefore, we do as well. */ + if (ctype) + ctype = TYPE_MAIN_VARIANT (ctype); + /* Update the declarator so that when we process it + again the correct type is present. */ + TREE_OPERAND (decl, 0) = ctype; + + if (ctype && TREE_CODE (TREE_OPERAND (decl, 1)) == TYPE_DECL + && constructor_name_p (DECL_NAME (TREE_OPERAND (decl, 1)), + ctype)) + TREE_OPERAND (decl, 1) = constructor_name (ctype); + next = &TREE_OPERAND (decl, 1); + decl = *next; + if (ctype) { - tree fns = TREE_OPERAND (decl, 0); + tree name = decl; - dname = fns; - if (TREE_CODE (dname) != IDENTIFIER_NODE) + if (TREE_CODE (name) == BIT_NOT_EXPR) + name = TREE_OPERAND (name, 0); + + if (!constructor_name_p (decl, ctype)) + ; + else if (decl == name) { - gcc_assert (is_overloaded_fn (dname)); - dname = DECL_NAME (get_first_fn (dname)); + sfk = sfk_constructor; + ctor_return_type = ctype; + } + else + { + sfk = sfk_destructor; + ctor_return_type = ctype; + flags = DTOR_FLAG; + TREE_OPERAND (decl, 0) = constructor_name (ctype); + next = &TREE_OPERAND (decl, 0); } } - /* Fall through. */ - - case IDENTIFIER_NODE: - if (TREE_CODE (decl) == IDENTIFIER_NODE) - dname = decl; + } + break; - if (C_IS_RESERVED_WORD (dname)) - { - error ("declarator-id missing; using reserved word %qD", - dname); - name = IDENTIFIER_POINTER (dname); - } - else if (!IDENTIFIER_TYPENAME_P (dname)) - name = IDENTIFIER_POINTER (dname); - else - { - gcc_assert (flags == NO_SPECIAL); - flags = TYPENAME_FLAG; - ctor_return_type = TREE_TYPE (dname); - sfk = sfk_conversion; - if (is_typename_at_global_scope (dname)) - name = IDENTIFIER_POINTER (dname); - else - name = "<invalid operator>"; - } - break; + case ERROR_MARK: + next = 0; + break; - default: - gcc_unreachable (); - } + case TYPE_DECL: + /* Parse error puts this typespec where + a declarator should go. */ + error ("`%T' specified as declarator-id", DECL_NAME (decl)); + if (TREE_TYPE (decl) == current_class_type) + error (" perhaps you want `%T' for a constructor", + current_class_name); + dname = DECL_NAME (decl); + name = IDENTIFIER_POINTER (dname); + + /* Avoid giving two errors for this. */ + IDENTIFIER_CLASS_VALUE (dname) = NULL_TREE; + + declspecs = tree_cons (NULL_TREE, integer_type_node, declspecs); + *next = dname; + next = 0; break; - case cdk_array: - case cdk_pointer: - case cdk_reference: - case cdk_ptrmem: + case BASELINK: + next = &BASELINK_FUNCTIONS (decl); break; - case cdk_error: + case TEMPLATE_DECL: + /* Sometimes, we see a template-name used as part of a + decl-specifier like in + std::allocator alloc; + Handle that gracefully. */ + error ("invalid use of template-name '%E' in a declarator", decl); return error_mark_node; - + break; + default: - gcc_unreachable (); + my_friendly_assert (0, 20020917); } - } - if (id_declarator->kind == cdk_id) - break; - } + } + } - /* [dcl.fct.edf] + /* A function definition's declarator must have the form of + a function declarator. */ - The declarator in a function-definition shall have the form - D1 ( parameter-declaration-clause) ... */ - if (funcdef_flag && innermost_code != cdk_function) - { - error ("function definition does not declare parameters"); - return error_mark_node; - } + if (funcdef_flag && innermost_code != CALL_EXPR) + return 0; if (((dname && IDENTIFIER_OPNAME_P (dname)) || flags == TYPENAME_FLAG) - && innermost_code != cdk_function - && ! (ctype && !declspecs->any_specifiers_p)) + && innermost_code != CALL_EXPR + && ! (ctype && declspecs == NULL_TREE)) { - error ("declaration of %qD as non-function", dname); - return error_mark_node; + error ("declaration of `%D' as non-function", dname); + return void_type_node; } /* Anything declared one level down from the top level @@ -7182,42 +6825,145 @@ grokdeclarator (const cp_declarator *declarator, if (name == NULL) name = decl_context == PARM ? "parameter" : "type name"; - /* If there were multiple types specified in the decl-specifier-seq, - issue an error message. */ - if (declspecs->multiple_types_p) - { - error ("two or more data types in declaration of %qs", name); - return error_mark_node; - } + /* Look through the decl specs and record which ones appear. + Some typespecs are defined as built-in typenames. + Others, the ones that are modifiers of other types, + are represented by bits in SPECBITS: set the bits for + the modifiers that appear. Storage class keywords are also in SPECBITS. - /* Extract the basic type from the decl-specifier-seq. */ - type = declspecs->type; - if (type == error_mark_node) - { - type = NULL_TREE; - type_was_error_mark_node = true; - } - /* If the entire declaration is itself tagged as deprecated then - suppress reports of deprecated items. */ - if (type && TREE_DEPRECATED (type) - && deprecated_state != DEPRECATED_SUPPRESS) - warn_deprecated_use (type); - if (type && TREE_CODE (type) == TYPE_DECL) - { - typedef_decl = type; - type = TREE_TYPE (typedef_decl); - } - /* No type at all: default to `int', and set DEFAULTED_INT - because it was not a user-defined typedef. */ - if (type == NULL_TREE && (signed_p || unsigned_p || long_p || short_p)) + If there is a typedef name or a type, store the type in TYPE. + This includes builtin typedefs such as `int'. + + Set EXPLICIT_INT if the type is `int' or `char' and did not + come from a user typedef. + + Set LONGLONG if `long' is mentioned twice. + + For C++, constructors and destructors have their own fast treatment. */ + + for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) { - /* These imply 'int'. */ - type = integer_type_node; - defaulted_int = 1; + int i; + tree id; + + /* Certain parse errors slip through. For example, + `int class;' is not caught by the parser. Try + weakly to recover here. */ + if (TREE_CODE (spec) != TREE_LIST) + return 0; + + id = TREE_VALUE (spec); + + /* If the entire declaration is itself tagged as deprecated then + suppress reports of deprecated items. */ + if (!adding_implicit_members && id && TREE_DEPRECATED (id)) + { + if (deprecated_state != DEPRECATED_SUPPRESS) + warn_deprecated_use (id); + } + + if (TREE_CODE (id) == IDENTIFIER_NODE) + { + if (id == ridpointers[(int) RID_INT] + || id == ridpointers[(int) RID_CHAR] + || id == ridpointers[(int) RID_BOOL] + || id == ridpointers[(int) RID_WCHAR]) + { + if (type) + { + if (id == ridpointers[(int) RID_BOOL]) + error ("`bool' is now a keyword"); + else + error ("extraneous `%T' ignored", id); + } + else + { + if (id == ridpointers[(int) RID_INT]) + explicit_int = 1; + else if (id == ridpointers[(int) RID_CHAR]) + explicit_char = 1; + type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id)); + } + goto found; + } + /* C++ aggregate types. */ + if (IDENTIFIER_HAS_TYPE_VALUE (id)) + { + if (type) + error ("multiple declarations `%T' and `%T'", type, id); + else + type = IDENTIFIER_TYPE_VALUE (id); + goto found; + } + + for (i = (int) RID_FIRST_MODIFIER; i <= (int) RID_LAST_MODIFIER; i++) + { + if (ridpointers[i] == id) + { + if (i == (int) RID_LONG && RIDBIT_SETP (i, specbits)) + { + if (pedantic && ! in_system_header && warn_long_long) + pedwarn ("ISO C++ does not support `long long'"); + if (longlong) + error ("`long long long' is too long for GCC"); + else + longlong = 1; + } + else if (RIDBIT_SETP (i, specbits)) + pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id)); + + /* Diagnose "__thread extern" or "__thread static". */ + if (RIDBIT_SETP (RID_THREAD, specbits)) + { + if (i == (int)RID_EXTERN) + error ("`__thread' before `extern'"); + else if (i == (int)RID_STATIC) + error ("`__thread' before `static'"); + } + + if (i == (int)RID_EXTERN + && TREE_PURPOSE (spec) == error_mark_node) + /* This extern was part of a language linkage. */ + extern_langp = 1; + + RIDBIT_SET (i, specbits); + goto found; + } + } + } + else if (TREE_CODE (id) == TYPE_DECL) + { + if (type) + error ("multiple declarations `%T' and `%T'", type, + TREE_TYPE (id)); + else + { + type = TREE_TYPE (id); + TREE_VALUE (spec) = type; + typedef_decl = id; + } + goto found; + } + if (type) + error ("two or more data types in declaration of `%s'", name); + else if (TREE_CODE (id) == IDENTIFIER_NODE) + { + tree t = lookup_name (id, 1); + if (!t || TREE_CODE (t) != TYPE_DECL) + error ("`%s' fails to be a typedef or built in type", + IDENTIFIER_POINTER (id)); + else + { + type = TREE_TYPE (t); + typedef_decl = t; + } + } + else if (id != error_mark_node) + /* Can't change CLASS nodes into RECORD nodes here! */ + type = id; + + found: ; } - /* Gather flags. */ - explicit_int = declspecs->explicit_int_p; - explicit_char = declspecs->explicit_char_p; #if 0 /* See the code below that used this. */ @@ -7226,9 +6972,19 @@ grokdeclarator (const cp_declarator *declarator, #endif typedef_type = type; + /* No type at all: default to `int', and set DEFAULTED_INT + because it was not a user-defined typedef. */ - if (sfk != sfk_conversion) - ctor_return_type = ctype; + if (type == NULL_TREE + && (RIDBIT_SETP (RID_SIGNED, specbits) + || RIDBIT_SETP (RID_UNSIGNED, specbits) + || RIDBIT_SETP (RID_LONG, specbits) + || RIDBIT_SETP (RID_SHORT, specbits))) + { + /* These imply 'int'. */ + type = integer_type_node; + defaulted_int = 1; + } if (sfk != sfk_none) type = check_special_function_return_type (sfk, type, @@ -7248,59 +7004,66 @@ grokdeclarator (const cp_declarator *declarator, && in_namespace == NULL_TREE && current_namespace == global_namespace); - if (type_was_error_mark_node) - /* We've already issued an error, don't complain more. */; - else if (in_system_header || flag_ms_extensions) + if (in_system_header || flag_ms_extensions) /* Allow it, sigh. */; else if (pedantic || ! is_main) - pedwarn ("ISO C++ forbids declaration of %qs with no type", name); + pedwarn ("ISO C++ forbids declaration of `%s' with no type", + name); else if (warn_return_type) - warning (0, "ISO C++ forbids declaration of %qs with no type", name); + warning ("ISO C++ forbids declaration of `%s' with no type", + name); type = integer_type_node; } - + ctype = NULL_TREE; /* Now process the modifiers that were specified and check for invalid combinations. */ /* Long double is a special combination. */ - if (long_p && !longlong && TYPE_MAIN_VARIANT (type) == double_type_node) + + if (RIDBIT_SETP (RID_LONG, specbits) + && TYPE_MAIN_VARIANT (type) == double_type_node) { - long_p = false; + RIDBIT_RESET (RID_LONG, specbits); type = build_qualified_type (long_double_type_node, cp_type_quals (type)); } /* Check all other uses of type modifiers. */ - if (unsigned_p || signed_p || long_p || short_p) + if (RIDBIT_SETP (RID_UNSIGNED, specbits) + || RIDBIT_SETP (RID_SIGNED, specbits) + || RIDBIT_SETP (RID_LONG, specbits) + || RIDBIT_SETP (RID_SHORT, specbits)) { int ok = 0; - if ((signed_p || unsigned_p) && TREE_CODE (type) != INTEGER_TYPE) - error ("%<signed%> or %<unsigned%> invalid for %qs", name); - else if (signed_p && unsigned_p) - error ("%<signed%> and %<unsigned%> specified together for %qs", name); - else if (longlong && TREE_CODE (type) != INTEGER_TYPE) - error ("%<long long%> invalid for %qs", name); - else if (long_p && TREE_CODE (type) == REAL_TYPE) - error ("%<long%> invalid for %qs", name); - else if (short_p && TREE_CODE (type) == REAL_TYPE) - error ("%<short%> invalid for %qs", name); - else if ((long_p || short_p) && TREE_CODE (type) != INTEGER_TYPE) - error ("%<long%> or %<short%> invalid for %qs", name); - else if ((long_p || short_p) && explicit_char) - error ("%<long%> or %<short%> specified with char for %qs", name); - else if (long_p && short_p) - error ("%<long%> and %<short%> specified together for %qs", name); + if (TREE_CODE (type) == REAL_TYPE) + error ("short, signed or unsigned invalid for `%s'", name); + else if (TREE_CODE (type) != INTEGER_TYPE) + error ("long, short, signed or unsigned invalid for `%s'", name); + else if (RIDBIT_SETP (RID_LONG, specbits) + && RIDBIT_SETP (RID_SHORT, specbits)) + error ("long and short specified together for `%s'", name); + else if ((RIDBIT_SETP (RID_LONG, specbits) + || RIDBIT_SETP (RID_SHORT, specbits)) + && explicit_char) + error ("long or short specified with char for `%s'", name); + else if ((RIDBIT_SETP (RID_LONG, specbits) + || RIDBIT_SETP (RID_SHORT, specbits)) + && TREE_CODE (type) == REAL_TYPE) + error ("long or short specified with floating type for `%s'", name); + else if (RIDBIT_SETP (RID_SIGNED, specbits) + && RIDBIT_SETP (RID_UNSIGNED, specbits)) + error ("signed and unsigned given together for `%s'", name); else { ok = 1; if (!explicit_int && !defaulted_int && !explicit_char && pedantic) { - pedwarn ("long, short, signed or unsigned used invalidly for %qs", + pedwarn ("long, short, signed or unsigned used invalidly for `%s'", name); if (flag_pedantic_errors) ok = 0; @@ -7310,17 +7073,24 @@ grokdeclarator (const cp_declarator *declarator, /* Discard the type modifiers if they are invalid. */ if (! ok) { - unsigned_p = false; - signed_p = false; - long_p = false; - short_p = false; + RIDBIT_RESET (RID_UNSIGNED, specbits); + RIDBIT_RESET (RID_SIGNED, specbits); + RIDBIT_RESET (RID_LONG, specbits); + RIDBIT_RESET (RID_SHORT, specbits); longlong = 0; } } + if (RIDBIT_SETP (RID_COMPLEX, specbits) + && TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE) + { + error ("complex invalid for `%s'", name); + RIDBIT_RESET (RID_COMPLEX, specbits); + } + /* Decide whether an integer type is signed or not. Optionally treat bitfields as signed by default. */ - if (unsigned_p + if (RIDBIT_SETP (RID_UNSIGNED, specbits) /* [class.bit] It is implementation-defined whether a plain (neither @@ -7330,20 +7100,21 @@ grokdeclarator (const cp_declarator *declarator, Naturally, we extend this to long long as well. Note that this does not include wchar_t. */ || (bitfield && !flag_signed_bitfields - && !signed_p + && RIDBIT_NOTSETP (RID_SIGNED, specbits) /* A typedef for plain `int' without `signed' can be controlled just like plain `int', but a typedef for `signed int' cannot be so controlled. */ && !(typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)) - && TREE_CODE (type) == INTEGER_TYPE + && (TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == CHAR_TYPE) && !same_type_p (TYPE_MAIN_VARIANT (type), wchar_type_node))) { if (longlong) type = long_long_unsigned_type_node; - else if (long_p) + else if (RIDBIT_SETP (RID_LONG, specbits)) type = long_unsigned_type_node; - else if (short_p) + else if (RIDBIT_SETP (RID_SHORT, specbits)) type = short_unsigned_type_node; else if (type == char_type_node) type = unsigned_char_type_node; @@ -7352,26 +7123,28 @@ grokdeclarator (const cp_declarator *declarator, else type = unsigned_type_node; } - else if (signed_p && type == char_type_node) + else if (RIDBIT_SETP (RID_SIGNED, specbits) + && type == char_type_node) type = signed_char_type_node; else if (longlong) type = long_long_integer_type_node; - else if (long_p) + else if (RIDBIT_SETP (RID_LONG, specbits)) type = long_integer_type_node; - else if (short_p) + else if (RIDBIT_SETP (RID_SHORT, specbits)) type = short_integer_type_node; - if (declspecs->specs[(int)ds_complex]) + if (RIDBIT_SETP (RID_COMPLEX, specbits)) { - if (TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE) - error ("complex invalid for %qs", name); /* If we just have "complex", it is equivalent to "complex double", but if any modifiers at all are specified it is the complex form of TYPE. E.g, "complex short" is "complex short int". */ - else if (defaulted_int && ! longlong - && ! (long_p || short_p || signed_p || unsigned_p)) + if (defaulted_int && ! longlong + && ! (RIDBIT_SETP (RID_LONG, specbits) + || RIDBIT_SETP (RID_SHORT, specbits) + || RIDBIT_SETP (RID_SIGNED, specbits) + || RIDBIT_SETP (RID_UNSIGNED, specbits))) type = complex_double_type_node; else if (type == integer_type_node) type = complex_integer_type_node; @@ -7386,72 +7159,67 @@ grokdeclarator (const cp_declarator *declarator, } type_quals = TYPE_UNQUALIFIED; - if (declspecs->specs[(int)ds_const]) + if (RIDBIT_SETP (RID_CONST, specbits)) type_quals |= TYPE_QUAL_CONST; - if (declspecs->specs[(int)ds_volatile]) + if (RIDBIT_SETP (RID_VOLATILE, specbits)) type_quals |= TYPE_QUAL_VOLATILE; - if (declspecs->specs[(int)ds_restrict]) + if (RIDBIT_SETP (RID_RESTRICT, specbits)) type_quals |= TYPE_QUAL_RESTRICT; if (sfk == sfk_conversion && type_quals != TYPE_UNQUALIFIED) - error ("qualifiers are not allowed on declaration of %<operator %T%>", - ctor_return_type); + error ("qualifiers are not allowed on declaration of `operator %T'", + ctor_return_type); - if (TREE_CODE (type) == FUNCTION_TYPE - && type_quals != TYPE_UNQUALIFIED) - { - /* This was an error in C++98 (cv-qualifiers cannot be added to - a function type), but DR 295 makes the code well-formed by - dropping the extra qualifiers. */ - if (pedantic) - { - tree bad_type = build_qualified_type (type, type_quals); - pedwarn ("ignoring %qV qualifiers added to function type %qT", - bad_type, type); - } - type_quals = TYPE_UNQUALIFIED; - } type_quals |= cp_type_quals (type); type = cp_build_qualified_type_real (type, type_quals, ((typedef_decl && !DECL_ARTIFICIAL (typedef_decl) - ? tf_ignore_bad_quals : 0) | tf_warning_or_error)); + ? tf_ignore_bad_quals : 0) | tf_error | tf_warning)); /* We might have ignored or rejected some of the qualifiers. */ type_quals = cp_type_quals (type); - + staticp = 0; - inlinep = !! declspecs->specs[(int)ds_inline]; - virtualp = !! declspecs->specs[(int)ds_virtual]; - explicitp = !! declspecs->specs[(int)ds_explicit]; + inlinep = !! RIDBIT_SETP (RID_INLINE, specbits); + virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits); + RIDBIT_RESET (RID_VIRTUAL, specbits); + explicitp = RIDBIT_SETP (RID_EXPLICIT, specbits) != 0; + RIDBIT_RESET (RID_EXPLICIT, specbits); - storage_class = declspecs->storage_class; - if (storage_class == sc_static) + if (RIDBIT_SETP (RID_STATIC, specbits)) staticp = 1 + (decl_context == FIELD); if (virtualp && staticp == 2) { - error ("member %qD cannot be declared both virtual and static", dname); - storage_class = sc_none; + error ("member `%D' cannot be declared both virtual and static", dname); + RIDBIT_RESET (RID_STATIC, specbits); staticp = 0; } - friendp = !! declspecs->specs[(int)ds_friend]; + friendp = RIDBIT_SETP (RID_FRIEND, specbits); + RIDBIT_RESET (RID_FRIEND, specbits); - if (dependent_name && !friendp) + if (dependant_name && !friendp) { - error ("%<%T::%D%> is not a valid declarator", ctype, dependent_name); - return error_mark_node; + error ("`%T::%D' is not a valid declarator", ctype, dependant_name); + return void_type_node; } + + /* Warn if two storage classes are given. Default to `auto'. */ - /* Issue errors about use of storage classes for parameters. */ - if (decl_context == PARM) + if (RIDBIT_ANY_SET (specbits)) { - if (declspecs->specs[(int)ds_typedef]) + if (RIDBIT_SETP (RID_STATIC, specbits)) nclasses++; + if (RIDBIT_SETP (RID_EXTERN, specbits) && !extern_langp) nclasses++; + if (RIDBIT_SETP (RID_THREAD, specbits)) nclasses++; + if (decl_context == PARM && nclasses > 0) + error ("storage class specifiers invalid in parameter declarations"); + if (RIDBIT_SETP (RID_TYPEDEF, specbits)) { - error ("typedef declaration invalid in parameter declaration"); - return error_mark_node; + if (decl_context == PARM) + error ("typedef declaration invalid in parameter declaration"); + nclasses++; } - else if (storage_class == sc_static - || storage_class == sc_extern - || thread_p) - error ("storage class specifiers invalid in parameter declarations"); + if (RIDBIT_SETP (RID_AUTO, specbits)) nclasses++; + if (RIDBIT_SETP (RID_REGISTER, specbits)) nclasses++; + if (!nclasses && !friendp && extern_langp) + nclasses++; } /* Give error if `virtual' is used outside of class declaration. */ @@ -7464,188 +7232,249 @@ grokdeclarator (const cp_declarator *declarator, /* Static anonymous unions are dealt with here. */ if (staticp && decl_context == TYPENAME - && declspecs->type - && ANON_AGGR_TYPE_P (declspecs->type)) + && TREE_CODE (declspecs) == TREE_LIST + && ANON_AGGR_TYPE_P (TREE_VALUE (declspecs))) decl_context = FIELD; /* Warn about storage classes that are invalid for certain kinds of declarations (parameters, typenames, etc.). */ - if (thread_p - && ((storage_class - && storage_class != sc_extern - && storage_class != sc_static) - || declspecs->specs[(int)ds_typedef])) - { - error ("multiple storage classes in declaration of %qs", name); - thread_p = false; - } - if (declspecs->conflicting_specifiers_p) - { - error ("conflicting specifiers in declaration of %qs", name); - storage_class = sc_none; - } - else if (decl_context != NORMAL - && ((storage_class != sc_none - && storage_class != sc_mutable) - || thread_p)) + + /* "static __thread" and "extern __thread" are allowed. */ + if (nclasses == 2 + && RIDBIT_SETP (RID_THREAD, specbits) + && (RIDBIT_SETP (RID_EXTERN, specbits) + || RIDBIT_SETP (RID_STATIC, specbits))) + nclasses = 1; + + if (nclasses > 1) + error ("multiple storage classes in declaration of `%s'", name); + else if (decl_context != NORMAL && nclasses > 0) { if ((decl_context == PARM || decl_context == CATCHPARM) - && (storage_class == sc_register - || storage_class == sc_auto)) + && (RIDBIT_SETP (RID_REGISTER, specbits) + || RIDBIT_SETP (RID_AUTO, specbits))) ; - else if (declspecs->specs[(int)ds_typedef]) + else if (RIDBIT_SETP (RID_TYPEDEF, specbits)) ; else if (decl_context == FIELD /* C++ allows static class elements. */ - && storage_class == sc_static) + && RIDBIT_SETP (RID_STATIC, specbits)) /* C++ also allows inlines and signed and unsigned elements, but in those cases we don't come in here. */ ; else { if (decl_context == FIELD) - error ("storage class specified for %qs", name); + { + tree tmp = NULL_TREE; + int op = 0; + + if (declarator) + { + /* Avoid trying to get an operand off an identifier node. */ + if (TREE_CODE (declarator) == IDENTIFIER_NODE) + tmp = declarator; + else + tmp = TREE_OPERAND (declarator, 0); + op = IDENTIFIER_OPNAME_P (tmp); + if (IDENTIFIER_TYPENAME_P (tmp)) + { + if (is_typename_at_global_scope (tmp)) + name = IDENTIFIER_POINTER (tmp); + else + name = "<invalid operator>"; + } + } + error ("storage class specified for %s `%s'", + op ? "member operator" : "field", + name); + } else { if (decl_context == PARM || decl_context == CATCHPARM) - error ("storage class specified for parameter %qs", name); + error ("storage class specified for parameter `%s'", name); else error ("storage class specified for typename"); } - if (storage_class == sc_register - || storage_class == sc_auto - || storage_class == sc_extern - || thread_p) - storage_class = sc_none; + RIDBIT_RESET (RID_REGISTER, specbits); + RIDBIT_RESET (RID_AUTO, specbits); + RIDBIT_RESET (RID_EXTERN, specbits); + RIDBIT_RESET (RID_THREAD, specbits); } } - else if (storage_class == sc_extern && initialized - && !funcdef_flag) + else if (RIDBIT_SETP (RID_EXTERN, specbits) && initialized && !funcdef_flag) { if (toplevel_bindings_p ()) { /* It's common practice (and completely valid) to have a const be initialized and declared extern. */ if (!(type_quals & TYPE_QUAL_CONST)) - warning (0, "%qs initialized and declared %<extern%>", name); + warning ("`%s' initialized and declared `extern'", name); } else - error ("%qs has both %<extern%> and initializer", name); + error ("`%s' has both `extern' and initializer", name); } - else if (storage_class == sc_extern && funcdef_flag + else if (RIDBIT_SETP (RID_EXTERN, specbits) && funcdef_flag && ! toplevel_bindings_p ()) - error ("nested function %qs declared %<extern%>", name); + error ("nested function `%s' declared `extern'", name); else if (toplevel_bindings_p ()) { - if (storage_class == sc_auto) - error ("top-level declaration of %qs specifies %<auto%>", name); + if (RIDBIT_SETP (RID_AUTO, specbits)) + error ("top-level declaration of `%s' specifies `auto'", name); } - else if (thread_p - && storage_class != sc_extern - && storage_class != sc_static) + else if (RIDBIT_SETP (RID_THREAD, specbits) + && !RIDBIT_SETP (RID_EXTERN, specbits) + && !RIDBIT_SETP (RID_STATIC, specbits)) { - error ("function-scope %qs implicitly auto and declared %<__thread%>", + error ("function-scope `%s' implicitly auto and declared `__thread'", name); - thread_p = false; + RIDBIT_RESET (RID_THREAD, specbits); } - if (storage_class && friendp) + if (nclasses > 0 && friendp) error ("storage class specifiers invalid in friend function declarations"); - if (!id_declarator) - unqualified_id = NULL_TREE; - else - { - unqualified_id = id_declarator->u.id.unqualified_name; - switch (TREE_CODE (unqualified_id)) - { - case BIT_NOT_EXPR: - unqualified_id - = constructor_name (TREE_OPERAND (unqualified_id, 0)); - break; + scope = get_scope_of_declarator (declarator); - case IDENTIFIER_NODE: - case TEMPLATE_ID_EXPR: - break; - - default: - gcc_unreachable (); - } - } + /* Now figure out the structure of the declarator proper. + Descend through it, creating more complex types, until we reach + the declared identifier (or NULL_TREE, in an abstract declarator). */ - /* Determine the type of the entity declared by recurring on the - declarator. */ - for (; declarator; declarator = declarator->declarator) + while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE + && TREE_CODE (declarator) != TEMPLATE_ID_EXPR) { - const cp_declarator *inner_declarator; - tree attrs; + /* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]), + an INDIRECT_REF (for *...), + a CALL_EXPR (for ...(...)), + an identifier (for the name being declared) + or a null pointer (for the place in an absolute declarator + where the name was omitted). + For the last two cases, we have just exited the loop. - if (type == error_mark_node) - return error_mark_node; + For C++ it could also be + a SCOPE_REF (for class :: ...). In this case, we have converted + sensible names to types, and those are the values we use to + qualify the member name. + an ADDR_EXPR (for &...), + a BIT_NOT_EXPR (for destructors) - attrs = declarator->attributes; - if (attrs) - { - int attr_flags; + At this point, TYPE is the type of elements of an array, + or for a function to return, or for a pointer to point to. + After this sequence of ifs, TYPE is the type of the + array or function or pointer, and DECLARATOR has had its + outermost layer removed. */ - attr_flags = 0; - if (declarator == NULL || declarator->kind == cdk_id) - attr_flags |= (int) ATTR_FLAG_DECL_NEXT; - if (declarator->kind == cdk_function) - attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; - if (declarator->kind == cdk_array) - attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; - returned_attrs = decl_attributes (&type, - chainon (returned_attrs, attrs), - attr_flags); + if (type == error_mark_node) + { + if (declarator == error_mark_node) + return error_mark_node; + else if (TREE_CODE (declarator) == SCOPE_REF) + declarator = TREE_OPERAND (declarator, 1); + else + declarator = TREE_OPERAND (declarator, 0); + continue; + } + if (quals != NULL_TREE + && (declarator == NULL_TREE + || TREE_CODE (declarator) != SCOPE_REF)) + { + if (ctype == NULL_TREE && TREE_CODE (type) == METHOD_TYPE) + ctype = TYPE_METHOD_BASETYPE (type); + if (ctype != NULL_TREE) + { + tree dummy = build_decl (TYPE_DECL, NULL_TREE, type); + grok_method_quals (ctype, dummy, quals); + type = TREE_TYPE (dummy); + quals = NULL_TREE; + } } - if (declarator->kind == cdk_id) - break; + switch (TREE_CODE (declarator)) + { + case TREE_LIST: + { + /* We encode a declarator with embedded attributes using + a TREE_LIST. */ + tree attrs = TREE_PURPOSE (declarator); + tree inner_decl; + int attr_flags; + + declarator = TREE_VALUE (declarator); + inner_decl = declarator; + while (inner_decl != NULL_TREE + && TREE_CODE (inner_decl) == TREE_LIST) + inner_decl = TREE_VALUE (inner_decl); + attr_flags = 0; + if (inner_decl == NULL_TREE + || TREE_CODE (inner_decl) == IDENTIFIER_NODE) + attr_flags |= (int) ATTR_FLAG_DECL_NEXT; + if (TREE_CODE (inner_decl) == CALL_EXPR) + attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; + if (TREE_CODE (inner_decl) == ARRAY_REF) + attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; + returned_attrs = decl_attributes (&type, + chainon (returned_attrs, attrs), + attr_flags); + } + break; - inner_declarator = declarator->declarator; + case ARRAY_REF: + { + tree size = TREE_OPERAND (declarator, 1); + declarator = TREE_OPERAND (declarator, 0); - switch (declarator->kind) - { - case cdk_array: - type = create_array_type_for_decl (dname, type, - declarator->u.array.bounds); + type = create_array_type_for_decl (dname, type, size); + + ctype = NULL_TREE; + } break; - case cdk_function: + case CALL_EXPR: { tree arg_types; int funcdecl_p; + tree inner_parms = CALL_DECLARATOR_PARMS (declarator); + tree inner_decl = TREE_OPERAND (declarator, 0); /* Declaring a function type. Make sure we have a valid type for the function to return. */ /* We now know that the TYPE_QUALS don't apply to the - decl, but to its return type. */ + decl, but to its return type. */ type_quals = TYPE_UNQUALIFIED; /* Warn about some types functions can't return. */ if (TREE_CODE (type) == FUNCTION_TYPE) { - error ("%qs declared as function returning a function", name); + error ("`%s' declared as function returning a function", name); type = integer_type_node; } if (TREE_CODE (type) == ARRAY_TYPE) { - error ("%qs declared as function returning an array", name); + error ("`%s' declared as function returning an array", name); type = integer_type_node; } + if (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF) + inner_decl = TREE_OPERAND (inner_decl, 1); + + if (inner_decl && TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR) + inner_decl = dname; + /* Pick up type qualifiers which should be applied to `this'. */ - memfn_quals = declarator->u.function.qualifiers; + quals = CALL_DECLARATOR_QUALS (declarator); /* Pick up the exception specifications. */ - raises = declarator->u.function.exception_specification; + raises = CALL_DECLARATOR_EXCEPTION_SPEC (declarator); /* Say it's a definition only for the CALL_EXPR closest to the identifier. */ - funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id; + funcdecl_p + = inner_decl + && (TREE_CODE (inner_decl) == IDENTIFIER_NODE + || TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR + || TREE_CODE (inner_decl) == BIT_NOT_EXPR); if (ctype == NULL_TREE && decl_context == FIELD @@ -7653,52 +7482,75 @@ grokdeclarator (const cp_declarator *declarator, && (friendp == 0 || dname == current_class_name)) ctype = current_class_type; - if (ctype && (sfk == sfk_constructor - || sfk == sfk_destructor)) + if (ctype && sfk == sfk_conversion) + TYPE_HAS_CONVERSION (ctype) = 1; + if (ctype && constructor_name_p (dname, ctype)) { /* We are within a class's scope. If our declarator name is the same as the class name, and we are defining a function, then it is a constructor/destructor, and therefore returns a void type. */ - /* ISO C++ 12.4/2. A destructor may not be declared - const or volatile. A destructor may not be - static. - - ISO C++ 12.1. A constructor may not be declared - const or volatile. A constructor may not be - virtual. A constructor may not be static. */ - if (staticp == 2) - error ((flags == DTOR_FLAG) - ? "destructor cannot be static member function" - : "constructor cannot be static member function"); - if (memfn_quals) + if (flags == DTOR_FLAG) { - error ((flags == DTOR_FLAG) - ? "destructors may not be cv-qualified" - : "constructors may not be cv-qualified"); - memfn_quals = TYPE_UNQUALIFIED; + /* ISO C++ 12.4/2. A destructor may not be + declared const or volatile. A destructor may + not be static. */ + if (staticp == 2) + error ("destructor cannot be static member function"); + if (quals) + { + error ("destructors may not be `%s'", + IDENTIFIER_POINTER (TREE_VALUE (quals))); + quals = NULL_TREE; + } + if (decl_context == FIELD) + { + if (! member_function_or_else (ctype, + current_class_type, + flags)) + return void_type_node; + } } - - if (decl_context == FIELD - && !member_function_or_else (ctype, - current_class_type, - flags)) - return error_mark_node; - - if (flags != DTOR_FLAG) + else /* It's a constructor. */ { - /* It's a constructor. */ if (explicitp == 1) explicitp = 2; + /* ISO C++ 12.1. A constructor may not be + declared const or volatile. A constructor may + not be virtual. A constructor may not be + static. */ + if (staticp == 2) + error ("constructor cannot be static member function"); if (virtualp) { pedwarn ("constructors cannot be declared virtual"); virtualp = 0; } - if (decl_context == FIELD - && sfk != sfk_constructor) - return error_mark_node; + if (quals) + { + error ("constructors may not be `%s'", + IDENTIFIER_POINTER (TREE_VALUE (quals))); + quals = NULL_TREE; + } + { + RID_BIT_TYPE tmp_bits; + memcpy (&tmp_bits, &specbits, sizeof (RID_BIT_TYPE)); + RIDBIT_RESET (RID_INLINE, tmp_bits); + RIDBIT_RESET (RID_STATIC, tmp_bits); + if (RIDBIT_ANY_SET (tmp_bits)) + error ("return value type specifier for constructor ignored"); + } + if (decl_context == FIELD) + { + if (! member_function_or_else (ctype, + current_class_type, + flags)) + return void_type_node; + TYPE_HAS_CONSTRUCTOR (ctype) = 1; + if (sfk != sfk_constructor) + return NULL_TREE; + } } if (decl_context == FIELD) staticp = 0; @@ -7706,228 +7558,287 @@ grokdeclarator (const cp_declarator *declarator, else if (friendp) { if (initialized) - error ("can't initialize friend function %qs", name); + error ("can't initialize friend function `%s'", name); if (virtualp) { /* Cannot be both friend and virtual. */ error ("virtual functions cannot be friends"); + RIDBIT_RESET (RID_FRIEND, specbits); friendp = 0; } if (decl_context == NORMAL) error ("friend declaration not in class definition"); if (current_function_decl && funcdef_flag) - error ("can't define friend function %qs in a local " - "class definition", - name); + error ("can't define friend function `%s' in a local class definition", + name); } - arg_types = grokparms (declarator->u.function.parameters, - &parms); + /* Construct the function type and go to the next + inner layer of declarator. */ + + declarator = TREE_OPERAND (declarator, 0); - if (inner_declarator - && inner_declarator->kind == cdk_id - && inner_declarator->u.id.sfk == sfk_destructor - && arg_types != void_list_node) + arg_types = grokparms (inner_parms, &parms); + + if (declarator && flags == DTOR_FLAG) { - error ("destructors may not have parameters"); - arg_types = void_list_node; - parms = NULL_TREE; + /* A destructor declared in the body of a class will + be represented as a BIT_NOT_EXPR. But, we just + want the underlying IDENTIFIER. */ + if (TREE_CODE (declarator) == BIT_NOT_EXPR) + declarator = TREE_OPERAND (declarator, 0); + + if (arg_types != void_list_node) + { + error ("destructors may not have parameters"); + arg_types = void_list_node; + parms = NULL_TREE; + } } + /* ANSI says that `const int foo ();' + does not make the function foo const. */ type = build_function_type (type, arg_types); } break; - case cdk_pointer: - case cdk_reference: - case cdk_ptrmem: + case ADDR_EXPR: + case INDIRECT_REF: /* Filter out pointers-to-references and references-to-references. We can get these if a TYPE_DECL is used. */ if (TREE_CODE (type) == REFERENCE_TYPE) { - error (declarator->kind == cdk_reference - ? "cannot declare reference to %q#T" - : "cannot declare pointer to %q#T", type); + error (TREE_CODE (declarator) == ADDR_EXPR + ? "cannot declare reference to `%#T'" + : "cannot declare pointer to `%#T'", type); type = TREE_TYPE (type); } - else if (VOID_TYPE_P (type)) - { - if (declarator->kind == cdk_reference) - error ("cannot declare reference to %q#T", type); - else if (declarator->kind == cdk_ptrmem) - error ("cannot declare pointer to %q#T member", type); - } + else if (VOID_TYPE_P (type) + && (ctype || TREE_CODE (declarator) == ADDR_EXPR)) + error (ctype ? "cannot declare pointer to `%#T' member" + : "cannot declare reference to `%#T'", type); + + /* Merge any constancy or volatility into the target type + for the pointer. */ /* We now know that the TYPE_QUALS don't apply to the decl, but to the target of the pointer. */ type_quals = TYPE_UNQUALIFIED; - if (declarator->kind == cdk_ptrmem - && (TREE_CODE (type) == FUNCTION_TYPE || memfn_quals)) - { - memfn_quals |= cp_type_quals (type); - type = build_memfn_type (type, - declarator->u.pointer.class_type, - memfn_quals); - memfn_quals = TYPE_UNQUALIFIED; - } - - if (declarator->kind == cdk_reference) + if (TREE_CODE (declarator) == ADDR_EXPR) { if (!VOID_TYPE_P (type)) type = build_reference_type (type); } else if (TREE_CODE (type) == METHOD_TYPE) type = build_ptrmemfunc_type (build_pointer_type (type)); - else if (declarator->kind == cdk_ptrmem) - { - gcc_assert (TREE_CODE (declarator->u.pointer.class_type) - != NAMESPACE_DECL); - if (declarator->u.pointer.class_type == error_mark_node) - /* We will already have complained. */ - type = error_mark_node; - else - type = build_ptrmem_type (declarator->u.pointer.class_type, - type); - } + else if (ctype) + type = build_ptrmem_type (ctype, type); else type = build_pointer_type (type); /* Process a list of type modifier keywords (such as const or volatile) that were given inside the `*' or `&'. */ - if (declarator->u.pointer.qualifiers) + if (TREE_TYPE (declarator)) { - type - = cp_build_qualified_type (type, - declarator->u.pointer.qualifiers); + tree typemodlist; + int erred = 0; + int constp = 0; + int volatilep = 0; + int restrictp = 0; + + for (typemodlist = TREE_TYPE (declarator); typemodlist; + typemodlist = TREE_CHAIN (typemodlist)) + { + tree qualifier = TREE_VALUE (typemodlist); + + if (qualifier == ridpointers[(int) RID_CONST]) + { + constp++; + type_quals |= TYPE_QUAL_CONST; + } + else if (qualifier == ridpointers[(int) RID_VOLATILE]) + { + volatilep++; + type_quals |= TYPE_QUAL_VOLATILE; + } + else if (qualifier == ridpointers[(int) RID_RESTRICT]) + { + restrictp++; + type_quals |= TYPE_QUAL_RESTRICT; + } + else if (!erred) + { + erred = 1; + error ("invalid type modifier within pointer declarator"); + } + } + if (constp > 1) + pedwarn ("duplicate `const'"); + if (volatilep > 1) + pedwarn ("duplicate `volatile'"); + if (restrictp > 1) + pedwarn ("duplicate `restrict'"); + type = cp_build_qualified_type (type, type_quals); type_quals = cp_type_quals (type); } + declarator = TREE_OPERAND (declarator, 0); ctype = NULL_TREE; break; - case cdk_error: - break; + case SCOPE_REF: + { + /* We have converted type names to NULL_TREE if the + name was bogus, or to a _TYPE node, if not. - default: - gcc_unreachable (); - } - } + The variable CTYPE holds the type we will ultimately + resolve to. The code here just needs to build + up appropriate member types. */ + tree sname = TREE_OPERAND (declarator, 1); + tree t; - if (unqualified_id && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR - && TREE_CODE (type) != FUNCTION_TYPE - && TREE_CODE (type) != METHOD_TYPE) - { - error ("template-id %qD used as a declarator", - unqualified_id); - unqualified_id = dname; - } + /* Destructors can have their visibilities changed as well. */ + if (TREE_CODE (sname) == BIT_NOT_EXPR) + sname = TREE_OPERAND (sname, 0); - /* If TYPE is a FUNCTION_TYPE, but the function name was explicitly - qualified with a class-name, turn it into a METHOD_TYPE, unless - we know that the function is static. We take advantage of this - opportunity to do other processing that pertains to entities - explicitly declared to be class members. Note that if DECLARATOR - is non-NULL, we know it is a cdk_id declarator; otherwise, we - would not have exited the loop above. */ - if (declarator - && declarator->u.id.qualifying_scope - && TYPE_P (declarator->u.id.qualifying_scope)) - { - tree t; - - ctype = declarator->u.id.qualifying_scope; - ctype = TYPE_MAIN_VARIANT (ctype); - t = ctype; - while (t != NULL_TREE && CLASS_TYPE_P (t)) - { - /* You're supposed to have one `template <...>' for every - template class, but you don't need one for a full - specialization. For example: - - template <class T> struct S{}; - template <> struct S<int> { void f(); }; - void S<int>::f () {} - - is correct; there shouldn't be a `template <>' for the - definition of `S<int>::f'. */ - if (CLASSTYPE_TEMPLATE_SPECIALIZATION (t) - && !any_dependent_template_arguments_p (CLASSTYPE_TI_ARGS (t))) - /* T is an explicit (not partial) specialization. All - containing classes must therefore also be explicitly - specialized. */ - break; - if ((CLASSTYPE_USE_TEMPLATE (t) || CLASSTYPE_IS_TEMPLATE (t)) - && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t))) - template_count += 1; + if (TREE_OPERAND (declarator, 0) == NULL_TREE) + { + /* We had a reference to a global decl, or + perhaps we were given a non-aggregate typedef, + in which case we cleared this out, and should just + keep going as though it wasn't there. */ + declarator = sname; + continue; + } + ctype = TREE_OPERAND (declarator, 0); - t = TYPE_MAIN_DECL (t); - t = DECL_CONTEXT (t); - } + t = ctype; + if (TREE_CODE (TREE_OPERAND (declarator, 1)) != INDIRECT_REF) + while (t != NULL_TREE && CLASS_TYPE_P (t)) + { + /* You're supposed to have one `template <...>' + for every template class, but you don't need one + for a full specialization. For example: + + template <class T> struct S{}; + template <> struct S<int> { void f(); }; + void S<int>::f () {} + + is correct; there shouldn't be a `template <>' for + the definition of `S<int>::f'. */ + if (CLASSTYPE_TEMPLATE_INFO (t) + && (CLASSTYPE_TEMPLATE_INSTANTIATION (t) + || uses_template_parms (CLASSTYPE_TI_ARGS (t))) + && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t))) + template_count += 1; + + t = TYPE_MAIN_DECL (t); + t = DECL_CONTEXT (t); + } - if (ctype == current_class_type) - { - if (friendp) - pedwarn ("member functions are implicitly friends of their class"); - else - pedwarn ("extra qualification %<%T::%> on member %qs", - ctype, name); - } - else if (/* If the qualifying type is already complete, then we - can skip the following checks. */ - !COMPLETE_TYPE_P (ctype) - && (/* If the function is being defined, then - qualifying type must certainly be complete. */ - funcdef_flag - /* A friend declaration of "T::f" is OK, even if - "T" is a template parameter. But, if this - function is not a friend, the qualifying type - must be a class. */ - || (!friendp && !CLASS_TYPE_P (ctype)) - /* For a declaration, the type need not be - complete, if either it is dependent (since there - is no meaningful definition of complete in that - case) or the qualifying class is currently being - defined. */ - || !(dependent_type_p (ctype) - || currently_open_class (ctype))) - /* Check that the qualifying type is complete. */ - && !complete_type_or_else (ctype, NULL_TREE)) - return error_mark_node; - else if (TREE_CODE (type) == FUNCTION_TYPE) - { - tree sname = declarator->u.id.unqualified_name; + if (sname == NULL_TREE) + goto done_scoping; - if (current_class_type - && (!friendp || funcdef_flag)) - { - error (funcdef_flag - ? "cannot define member function %<%T::%s%> within %<%T%>" - : "cannot declare member function %<%T::%s%> within %<%T%>", - ctype, name, current_class_type); - return error_mark_node; - } + if (TREE_CODE (sname) == IDENTIFIER_NODE) + { + /* This is the `standard' use of the scoping operator: + basetype :: member . */ - if (TREE_CODE (sname) == IDENTIFIER_NODE - && NEW_DELETE_OPNAME_P (sname)) - /* Overloaded operator new and operator delete - are always static functions. */ - ; - else - type = build_memfn_type (type, ctype, memfn_quals); - } - else if (declspecs->specs[(int)ds_typedef] - && current_class_type) - { - error ("cannot declare member %<%T::%s%> within %qT", - ctype, name, current_class_type); - return error_mark_node; + if (ctype == current_class_type) + { + /* class A { + void A::f (); + }; + + Is this ill-formed? */ + + if (pedantic) + pedwarn ("extra qualification `%T::' on member `%s' ignored", + ctype, name); + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (NEW_DELETE_OPNAME_P (sname)) + /* Overloaded operator new and operator delete + are always static functions. */ + ; + else if (current_class_type == NULL_TREE || friendp) + type + = build_method_type_directly (ctype, + TREE_TYPE (type), + TYPE_ARG_TYPES (type)); + else + { + error ("cannot declare member function `%T::%s' within `%T'", + ctype, name, current_class_type); + return error_mark_node; + } + } + else if (RIDBIT_SETP (RID_TYPEDEF, specbits) + || COMPLETE_TYPE_P (complete_type (ctype))) + { + /* Have to move this code elsewhere in this function. + this code is used for i.e., typedef int A::M; M *pm; + + It is? How? jason 10/2/94 */ + + if (current_class_type) + { + error ("cannot declare member `%T::%s' within `%T'", + ctype, name, current_class_type); + return void_type_node; + } + } + else + { + cxx_incomplete_type_error (NULL_TREE, ctype); + return error_mark_node; + } + + declarator = sname; + } + else if (TREE_CODE (sname) == SCOPE_REF) + abort (); + else + { + done_scoping: + declarator = TREE_OPERAND (declarator, 1); + if (declarator && TREE_CODE (declarator) == CALL_EXPR) + /* In this case, we will deal with it later. */ + ; + else if (TREE_CODE (type) == FUNCTION_TYPE) + type = build_method_type_directly (ctype, + TREE_TYPE (type), + TYPE_ARG_TYPES (type)); + } + } + break; + + case BIT_NOT_EXPR: + declarator = TREE_OPERAND (declarator, 0); + break; + + case BASELINK: + declarator = BASELINK_FUNCTIONS (declarator); + break; + + case RECORD_TYPE: + case UNION_TYPE: + case ENUMERAL_TYPE: + declarator = NULL_TREE; + break; + + case ERROR_MARK: + declarator = NULL_TREE; + break; + + default: + abort (); } } - /* Now TYPE has the actual type. */ - if (returned_attrs) { if (attrlist) @@ -7936,70 +7847,87 @@ grokdeclarator (const cp_declarator *declarator, attrlist = &returned_attrs; } + /* Now TYPE has the actual type. */ + /* Did array size calculations overflow? */ if (TREE_CODE (type) == ARRAY_TYPE && COMPLETE_TYPE_P (type) - && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST - && TREE_OVERFLOW (TYPE_SIZE_UNIT (type))) + && TREE_OVERFLOW (TYPE_SIZE (type))) { - error ("size of array %qs is too large", name); + error ("size of array `%s' is too large", name); /* If we proceed with the array type as it is, we'll eventually crash in tree_low_cst(). */ type = error_mark_node; } if ((decl_context == FIELD || decl_context == PARM) - && !processing_template_decl - && variably_modified_type_p (type, NULL_TREE)) + && !processing_template_decl + && variably_modified_type_p (type)) { if (decl_context == FIELD) - error ("data member may not have variably modified type %qT", type); + error ("data member may not have variably modified type `%T'", type); else - error ("parameter may not have variably modified type %qT", type); + error ("parameter may not have variably modified type `%T'", type); type = error_mark_node; } if (explicitp == 1 || (explicitp && friendp)) { /* [dcl.fct.spec] The explicit specifier shall only be used in - declarations of constructors within a class definition. */ - error ("only declarations of constructors can be %<explicit%>"); + declarations of constructors within a class definition. */ + error ("only declarations of constructors can be `explicit'"); explicitp = 0; } - if (storage_class == sc_mutable) + if (RIDBIT_SETP (RID_MUTABLE, specbits)) { if (decl_context != FIELD || friendp) + { + error ("non-member `%s' cannot be declared `mutable'", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } + else if (decl_context == TYPENAME || RIDBIT_SETP (RID_TYPEDEF, specbits)) { - error ("non-member %qs cannot be declared %<mutable%>", name); - storage_class = sc_none; - } - else if (decl_context == TYPENAME || declspecs->specs[(int)ds_typedef]) - { - error ("non-object member %qs cannot be declared %<mutable%>", name); - storage_class = sc_none; + error ("non-object member `%s' cannot be declared `mutable'", name); + RIDBIT_RESET (RID_MUTABLE, specbits); } else if (TREE_CODE (type) == FUNCTION_TYPE - || TREE_CODE (type) == METHOD_TYPE) - { - error ("function %qs cannot be declared %<mutable%>", name); - storage_class = sc_none; - } + || TREE_CODE (type) == METHOD_TYPE) + { + error ("function `%s' cannot be declared `mutable'", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } else if (staticp) { - error ("static %qs cannot be declared %<mutable%>", name); - storage_class = sc_none; + error ("static `%s' cannot be declared `mutable'", name); + RIDBIT_RESET (RID_MUTABLE, specbits); } else if (type_quals & TYPE_QUAL_CONST) { - error ("const %qs cannot be declared %<mutable%>", name); - storage_class = sc_none; + error ("const `%s' cannot be declared `mutable'", name); + RIDBIT_RESET (RID_MUTABLE, specbits); } } + if (declarator == NULL_TREE + || TREE_CODE (declarator) == IDENTIFIER_NODE + || (TREE_CODE (declarator) == TEMPLATE_ID_EXPR + && (TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == METHOD_TYPE))) + /* OK */; + else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) + { + error ("template-id `%D' used as a declarator", declarator); + declarator = dname; + } + else + /* Unexpected declarator format. */ + abort (); + /* If this is declaring a typedef name, return a TYPE_DECL. */ - if (declspecs->specs[(int)ds_typedef] && decl_context != TYPENAME) + + if (RIDBIT_SETP (RID_TYPEDEF, specbits) && decl_context != TYPENAME) { tree decl; @@ -8008,49 +7936,28 @@ grokdeclarator (const cp_declarator *declarator, if (current_lang_name == lang_name_java) TYPE_FOR_JAVA (type) = 1; - /* This declaration: - - typedef void f(int) const; - - declares a function type which is not a member of any - particular class, but which is cv-qualified; for - example "f S::*" declares a pointer to a const-qualified - member function of S. We record the cv-qualification in the - function type. */ - if (memfn_quals && TREE_CODE (type) == FUNCTION_TYPE) - type = cp_build_qualified_type (type, memfn_quals); - if (decl_context == FIELD) - decl = build_lang_decl (TYPE_DECL, unqualified_id, type); + { + if (constructor_name_p (declarator, current_class_type)) + pedwarn ("ISO C++ forbids nested type `%D' with same name as enclosing class", + declarator); + decl = build_lang_decl (TYPE_DECL, declarator, type); + } else - decl = build_decl (TYPE_DECL, unqualified_id, type); - if (id_declarator && declarator->u.id.qualifying_scope) - error ("%Jtypedef name may not be a nested-name-specifier", decl); - - if (decl_context != FIELD) { + decl = build_decl (TYPE_DECL, declarator, type); + if (in_namespace || ctype) + error ("%Jtypedef name may not be a nested-name-specifier", decl); if (!current_function_decl) DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); - else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (current_function_decl) - || (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P - (current_function_decl))) - /* The TYPE_DECL is "abstract" because there will be - clones of this constructor/destructor, and there will - be copies of this TYPE_DECL generated in those - clones. */ - DECL_ABSTRACT (decl) = 1; - } - else if (constructor_name_p (unqualified_id, current_class_type)) - pedwarn ("ISO C++ forbids nested type %qD with same name " - "as enclosing class", - unqualified_id); - + } + /* If the user declares "typedef struct {...} foo" then the struct will have an anonymous name. Fill that name in now. Nothing can refer to it, so nothing needs know about the name change. */ if (type != error_mark_node - && unqualified_id + && declarator && TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL && TYPE_ANONYMOUS_P (type) @@ -8062,6 +7969,7 @@ grokdeclarator (const cp_declarator *declarator, tree t; /* Replace the anonymous name with the real name everywhere. */ + lookup_tag_reverse (type, declarator); for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) if (TYPE_NAME (t) == oldname) TYPE_NAME (t) = decl; @@ -8080,17 +7988,25 @@ grokdeclarator (const cp_declarator *declarator, type with external linkage have external linkage. */ } - /* Any qualifiers on a function type typedef have already been - dealt with. */ - if (memfn_quals && !ctype && TREE_CODE (type) == FUNCTION_TYPE) - memfn_quals = TYPE_UNQUALIFIED; + if (quals) + { + if (ctype == NULL_TREE) + { + if (TREE_CODE (type) != METHOD_TYPE) + error ("%Jinvalid type qualifier for non-member function type", + decl); + else + ctype = TYPE_METHOD_BASETYPE (type); + } + if (ctype != NULL_TREE) + grok_method_quals (ctype, decl, quals); + } - if (signed_p + if (RIDBIT_SETP (RID_SIGNED, specbits) || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; - bad_specifiers (decl, "type", virtualp, - memfn_quals != TYPE_UNQUALIFIED, + bad_specifiers (decl, "type", virtualp, quals != NULL_TREE, inlinep, friendp, raises != NULL_TREE); return decl; @@ -8108,7 +8024,7 @@ grokdeclarator (const cp_declarator *declarator, /* Detect where we're using a typedef of function type to declare a function. PARMS will not be set, so we must create it now. */ - + if (type == typedef_type && TREE_CODE (type) == FUNCTION_TYPE) { tree decls = NULL_TREE; @@ -8121,25 +8037,8 @@ grokdeclarator (const cp_declarator *declarator, TREE_CHAIN (decl) = decls; decls = decl; } - + parms = nreverse (decls); - - if (decl_context != TYPENAME) - { - /* A cv-qualifier-seq shall only be part of the function type - for a non-static member function. [8.3.5/4 dcl.fct] */ - if (cp_type_quals (type) != TYPE_UNQUALIFIED - && (current_class_type == NULL_TREE || staticp) ) - { - error ("qualified function types cannot be used to declare %s functions", - (staticp? "static member" : "free")); - type = TYPE_MAIN_VARIANT (type); - } - - /* The qualifiers on the function type become the qualifiers on - the non-static member function. */ - memfn_quals |= cp_type_quals (type); - } } /* If this is a type name (such as, in a cast or sizeof), @@ -8162,7 +8061,7 @@ grokdeclarator (const cp_declarator *declarator, } if (inlinep) { - error ("%<inline%> specified for friend class declaration"); + error ("`inline' specified for friend class declaration"); inlinep = 0; } @@ -8172,12 +8071,12 @@ grokdeclarator (const cp_declarator *declarator, if (TREE_CODE (type) == TEMPLATE_TYPE_PARM) pedwarn ("template parameters cannot be friends"); else if (TREE_CODE (type) == TYPENAME_TYPE) - pedwarn ("friend declaration requires class-key, " - "i.e. %<friend class %T::%D%>", + pedwarn ("friend declaration requires class-key, " + "i.e. `friend class %T::%D'", TYPE_CONTEXT (type), TYPENAME_TYPE_FULLNAME (type)); else - pedwarn ("friend declaration requires class-key, " - "i.e. %<friend %#T%>", + pedwarn ("friend declaration requires class-key, " + "i.e. `friend %#T'", type); } @@ -8189,54 +8088,55 @@ grokdeclarator (const cp_declarator *declarator, make_friend_class (current_class_type, TYPE_MAIN_VARIANT (type), /*complain=*/true); else - error ("trying to make class %qT a friend of global scope", - type); + error ("trying to make class `%T' a friend of global scope", + type); type = void_type_node; } } - else if (memfn_quals) + else if (quals) { if (ctype == NULL_TREE) { if (TREE_CODE (type) != METHOD_TYPE) - error ("invalid qualifiers on non-member function type"); + error ("invalid qualifiers on non-member function type"); else - ctype = TYPE_METHOD_BASETYPE (type); + ctype = TYPE_METHOD_BASETYPE (type); } if (ctype) - type = build_memfn_type (type, ctype, memfn_quals); + { + tree dummy = build_decl (TYPE_DECL, declarator, type); + grok_method_quals (ctype, dummy, quals); + type = TREE_TYPE (dummy); + } } return type; } - else if (unqualified_id == NULL_TREE && decl_context != PARM + else if (declarator == NULL_TREE && decl_context != PARM && decl_context != CATCHPARM && TREE_CODE (type) != UNION_TYPE && ! bitfield) { - error ("abstract declarator %qT used as declaration", type); + error ("abstract declarator `%T' used as declaration", type); return error_mark_node; } /* Only functions may be declared using an operator-function-id. */ - if (unqualified_id - && IDENTIFIER_OPNAME_P (unqualified_id) + if (declarator + && TREE_CODE (declarator) == IDENTIFIER_NODE + && IDENTIFIER_OPNAME_P (declarator) && TREE_CODE (type) != FUNCTION_TYPE && TREE_CODE (type) != METHOD_TYPE) { - error ("declaration of %qD as non-function", unqualified_id); + error ("declaration of `%D' as non-function", declarator); return error_mark_node; } /* We don't check parameter types here because we can emit a better error message later. */ if (decl_context != PARM) - { - type = check_var_type (unqualified_id, type); - if (type == error_mark_node) - return error_mark_node; - } + type = check_var_type (declarator, type); /* Now create the decl, which may be a VAR_DECL, a PARM_DECL or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */ @@ -8244,7 +8144,7 @@ grokdeclarator (const cp_declarator *declarator, if (decl_context == PARM || decl_context == CATCHPARM) { if (ctype || in_namespace) - error ("cannot use %<::%> in parameter declaration"); + error ("cannot use `::' in parameter declaration"); /* A parameter declared as an array of T is really a pointer to T. One declared as a function is really a pointer to a function. @@ -8265,10 +8165,9 @@ grokdeclarator (const cp_declarator *declarator, if (decl_context == PARM) { - decl = cp_build_parm_decl (unqualified_id, type); + decl = cp_build_parm_decl (declarator, type); - bad_specifiers (decl, "parameter", virtualp, - memfn_quals != TYPE_UNQUALIFIED, + bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE, inlinep, friendp, raises != NULL_TREE); } else if (decl_context == FIELD) @@ -8290,14 +8189,23 @@ grokdeclarator (const cp_declarator *declarator, else if (in_namespace && !friendp) { /* Something like struct S { int N::j; }; */ - error ("invalid use of %<::%>"); - return error_mark_node; + error ("invalid use of `::'"); + decl = NULL_TREE; } else if (TREE_CODE (type) == FUNCTION_TYPE) { int publicp = 0; tree function_context; + /* We catch the others as conflicts with the builtin + typedefs. */ + if (friendp && declarator == ridpointers[(int) RID_SIGNED]) + { + error ("function `%D' cannot be declared friend", + declarator); + friendp = 0; + } + if (friendp == 0) { if (ctype == NULL_TREE) @@ -8305,54 +8213,33 @@ grokdeclarator (const cp_declarator *declarator, if (ctype == NULL_TREE) { - error ("can't make %qD into a method -- not in a class", - unqualified_id); - return error_mark_node; + error ("can't make `%D' into a method -- not in a class", + declarator); + return void_type_node; } /* ``A union may [ ... ] not [ have ] virtual functions.'' ARM 9.5 */ if (virtualp && TREE_CODE (ctype) == UNION_TYPE) { - error ("function %qD declared virtual inside a union", - unqualified_id); - return error_mark_node; + error ("function `%D' declared virtual inside a union", + declarator); + return void_type_node; } - if (NEW_DELETE_OPNAME_P (unqualified_id)) + if (NEW_DELETE_OPNAME_P (declarator)) { if (virtualp) { - error ("%qD cannot be declared virtual, since it " - "is always static", - unqualified_id); + error ("`%D' cannot be declared virtual, since it is always static", + declarator); virtualp = 0; } } else if (staticp < 2) - type = build_memfn_type (type, ctype, memfn_quals); - } - - /* Check that the name used for a destructor makes sense. */ - if (sfk == sfk_destructor) - { - if (!ctype) - { - gcc_assert (friendp); - error ("expected qualified name in friend declaration " - "for destructor %qD", - id_declarator->u.id.unqualified_name); - return error_mark_node; - } - - if (!same_type_p (TREE_OPERAND - (id_declarator->u.id.unqualified_name, 0), - ctype)) - { - error ("declaration of %qD as member of %qT", - id_declarator->u.id.unqualified_name, ctype); - return error_mark_node; - } + type = build_method_type_directly (ctype, + TREE_TYPE (type), + TYPE_ARG_TYPES (type)); } /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */ @@ -8361,16 +8248,15 @@ grokdeclarator (const cp_declarator *declarator, publicp = (! friendp || ! staticp) && function_context == NULL_TREE; decl = grokfndecl (ctype, type, - TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR - ? unqualified_id : dname, + TREE_CODE (declarator) != TEMPLATE_ID_EXPR + ? declarator : dname, parms, - unqualified_id, - virtualp, flags, memfn_quals, raises, + declarator, + virtualp, flags, quals, raises, friendp ? -1 : 0, friendp, publicp, inlinep, - sfk, - funcdef_flag, template_count, in_namespace, attrlist); + funcdef_flag, template_count, in_namespace); if (decl == NULL_TREE) - return error_mark_node; + return decl; #if 0 /* This clobbers the attrs stored in `decl' from `attrlist'. */ /* The decl and setting of decl_attr is also turned off. */ @@ -8409,44 +8295,44 @@ grokdeclarator (const cp_declarator *declarator, /* All method decls are public, so tell grokfndecl to set TREE_PUBLIC, also. */ decl = grokfndecl (ctype, type, - TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR - ? unqualified_id : dname, + TREE_CODE (declarator) != TEMPLATE_ID_EXPR + ? declarator : dname, parms, - unqualified_id, - virtualp, flags, memfn_quals, raises, - friendp ? -1 : 0, friendp, 1, 0, sfk, - funcdef_flag, template_count, in_namespace, - attrlist); + declarator, + virtualp, flags, quals, raises, + friendp ? -1 : 0, friendp, 1, 0, funcdef_flag, + template_count, in_namespace); if (decl == NULL_TREE) - return error_mark_node; + return NULL_TREE; } else if (!staticp && !dependent_type_p (type) && !COMPLETE_TYPE_P (complete_type (type)) && (TREE_CODE (type) != ARRAY_TYPE || initialized == 0)) { - if (unqualified_id) - error ("field %qD has incomplete type", unqualified_id); + if (declarator) + error ("field `%D' has incomplete type", declarator); else - error ("name %qT has incomplete type", type); + error ("name `%T' has incomplete type", type); /* If we're instantiating a template, tell them which instantiation made the field's type be incomplete. */ if (current_class_type && TYPE_NAME (current_class_type) && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (current_class_type)) - && declspecs->type - && declspecs->type == type) - error (" in instantiation of template %qT", - current_class_type); + && declspecs && TREE_VALUE (declspecs) + && TREE_TYPE (TREE_VALUE (declspecs)) == type) + error (" in instantiation of template `%T'", + current_class_type); - return error_mark_node; + type = error_mark_node; + decl = NULL_TREE; } else { if (friendp) { - error ("%qE is neither function nor member function; " - "cannot be declared friend", unqualified_id); + error ("`%s' is neither function nor member function; cannot be declared friend", + IDENTIFIER_POINTER (declarator)); friendp = 0; } decl = NULL_TREE; @@ -8456,25 +8342,24 @@ grokdeclarator (const cp_declarator *declarator, { /* Friends are treated specially. */ if (ctype == current_class_type) - ; /* We already issued a pedwarn. */ - else if (decl && DECL_NAME (decl)) + warning ("member functions are implicitly friends of their class"); + else if (decl && DECL_NAME (decl)) { if (template_class_depth (current_class_type) == 0) { decl = check_explicit_specialization - (unqualified_id, decl, template_count, - 2 * funcdef_flag + 4); + (declarator, decl, template_count, + 2 * (funcdef_flag != 0) + 4); if (decl == error_mark_node) return error_mark_node; } - - decl = do_friend (ctype, unqualified_id, decl, - *attrlist, flags, - funcdef_flag); + + decl = do_friend (ctype, declarator, decl, + *attrlist, flags, quals, funcdef_flag); return decl; } else - return error_mark_node; + return void_type_node; } /* Structure field. It may not be a function, except for C++. */ @@ -8497,60 +8382,46 @@ grokdeclarator (const cp_declarator *declarator, the rest of the compiler does not correctly handle the initialization unless the member is static so we make it static below. */ - pedwarn ("ISO C++ forbids initialization of member %qD", - unqualified_id); - pedwarn ("making %qD static", unqualified_id); + pedwarn ("ISO C++ forbids initialization of member `%D'", + declarator); + pedwarn ("making `%D' static", declarator); staticp = 1; } if (uses_template_parms (type)) /* We'll check at instantiation time. */ ; - else if (check_static_variable_definition (unqualified_id, + else if (check_static_variable_definition (declarator, type)) /* If we just return the declaration, crashes will sometimes occur. We therefore return void_type_node, as if this was a friend declaration, to cause callers to completely ignore this declaration. */ - return error_mark_node; + return void_type_node; } if (staticp) { /* C++ allows static class members. All other work for this is done by grokfield. */ - decl = build_lang_decl (VAR_DECL, unqualified_id, type); - set_linkage_for_static_data_member (decl); - /* Even if there is an in-class initialization, DECL - is considered undefined until an out-of-class - definition is provided. */ - DECL_EXTERNAL (decl) = 1; - - if (thread_p) - { - if (targetm.have_tls) - DECL_TLS_MODEL (decl) = decl_default_tls_model (decl); - else - /* A mere warning is sure to result in improper - semantics at runtime. Don't bother to allow this to - compile. */ - error ("thread-local storage not supported for this target"); - } + decl = build_lang_decl (VAR_DECL, declarator, type); + TREE_STATIC (decl) = 1; + /* In class context, 'static' means public access. */ + TREE_PUBLIC (decl) = DECL_EXTERNAL (decl) = 1; } else { - decl = build_decl (FIELD_DECL, unqualified_id, type); + decl = build_decl (FIELD_DECL, declarator, type); DECL_NONADDRESSABLE_P (decl) = bitfield; - if (storage_class == sc_mutable) + if (RIDBIT_SETP (RID_MUTABLE, specbits)) { DECL_MUTABLE_P (decl) = 1; - storage_class = sc_none; + RIDBIT_RESET (RID_MUTABLE, specbits); } } - bad_specifiers (decl, "field", virtualp, - memfn_quals != TYPE_UNQUALIFIED, + bad_specifiers (decl, "field", virtualp, quals != NULL_TREE, inlinep, friendp, raises != NULL_TREE); } } @@ -8560,63 +8431,61 @@ grokdeclarator (const cp_declarator *declarator, tree original_name; int publicp = 0; - if (!unqualified_id) - return error_mark_node; + if (! declarator) + return NULL_TREE; - if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR) + if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) original_name = dname; else - original_name = unqualified_id; + original_name = declarator; - if (storage_class == sc_auto) - error ("storage class %<auto%> invalid for function %qs", name); - else if (storage_class == sc_register) - error ("storage class %<register%> invalid for function %qs", name); - else if (thread_p) - error ("storage class %<__thread%> invalid for function %qs", name); + if (RIDBIT_SETP (RID_AUTO, specbits)) + error ("storage class `auto' invalid for function `%s'", name); + else if (RIDBIT_SETP (RID_REGISTER, specbits)) + error ("storage class `register' invalid for function `%s'", name); + else if (RIDBIT_SETP (RID_THREAD, specbits)) + error ("storage class `__thread' invalid for function `%s'", name); /* Function declaration not at top level. Storage classes other than `extern' are not allowed and `extern' makes no difference. */ if (! toplevel_bindings_p () - && (storage_class == sc_static - || declspecs->specs[(int)ds_inline]) + && (RIDBIT_SETP (RID_STATIC, specbits) + || RIDBIT_SETP (RID_INLINE, specbits)) && pedantic) { - if (storage_class == sc_static) - pedwarn ("%<static%> specified invalid for function %qs " - "declared out of global scope", name); + if (RIDBIT_SETP (RID_STATIC, specbits)) + pedwarn ("storage class `static' invalid for function `%s' declared out of global scope", name); else - pedwarn ("%<inline%> specifier invalid for function %qs " - "declared out of global scope", name); + pedwarn ("storage class `inline' invalid for function `%s' declared out of global scope", name); } if (ctype == NULL_TREE) { if (virtualp) { - error ("virtual non-class function %qs", name); + error ("virtual non-class function `%s'", name); virtualp = 0; } } else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2 && !NEW_DELETE_OPNAME_P (original_name)) - type = build_method_type_directly (ctype, + type = build_method_type_directly (ctype, TREE_TYPE (type), TYPE_ARG_TYPES (type)); /* Record presence of `static'. */ publicp = (ctype != NULL_TREE - || storage_class == sc_extern - || storage_class != sc_static); + || RIDBIT_SETP (RID_EXTERN, specbits) + || !RIDBIT_SETP (RID_STATIC, specbits)); - decl = grokfndecl (ctype, type, original_name, parms, unqualified_id, - virtualp, flags, memfn_quals, raises, + decl = grokfndecl (ctype, type, original_name, parms, declarator, + virtualp, flags, quals, raises, 1, friendp, - publicp, inlinep, sfk, funcdef_flag, - template_count, in_namespace, attrlist); + publicp, inlinep, funcdef_flag, + template_count, in_namespace); if (decl == NULL_TREE) - return error_mark_node; + return NULL_TREE; if (staticp == 1) { @@ -8626,8 +8495,7 @@ grokdeclarator (const cp_declarator *declarator, declaring main to be static. */ if (TREE_CODE (type) == METHOD_TYPE) { - pedwarn ("cannot declare member function %qD to have " - "static linkage", decl); + pedwarn ("cannot declare member function `%D' to have static linkage", decl); invalid_static = 1; } else if (current_function_decl) @@ -8640,7 +8508,7 @@ grokdeclarator (const cp_declarator *declarator, if (invalid_static) { staticp = 0; - storage_class = sc_none; + RIDBIT_RESET (RID_STATIC, specbits); } } } @@ -8649,13 +8517,11 @@ grokdeclarator (const cp_declarator *declarator, /* It's a variable. */ /* An uninitialized decl with `extern' is a reference. */ - decl = grokvardecl (type, unqualified_id, - declspecs, + decl = grokvardecl (type, declarator, &specbits, initialized, (type_quals & TYPE_QUAL_CONST) != 0, ctype ? ctype : in_namespace); - bad_specifiers (decl, "variable", virtualp, - memfn_quals != TYPE_UNQUALIFIED, + bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE, inlinep, friendp, raises != NULL_TREE); if (ctype) @@ -8663,41 +8529,43 @@ grokdeclarator (const cp_declarator *declarator, DECL_CONTEXT (decl) = ctype; if (staticp == 1) { - pedwarn ("%<static%> may not be used when defining " - "(as opposed to declaring) a static data member"); - staticp = 0; - storage_class = sc_none; + pedwarn ("`static' may not be used when defining (as opposed to declaring) a static data member"); + staticp = 0; + RIDBIT_RESET (RID_STATIC, specbits); } - if (storage_class == sc_register && TREE_STATIC (decl)) + if (RIDBIT_SETP (RID_REGISTER, specbits) && TREE_STATIC (decl)) { - error ("static member %qD declared %<register%>", decl); - storage_class = sc_none; + error ("static member `%D' declared `register'", decl); + RIDBIT_RESET (RID_REGISTER, specbits); } - if (storage_class == sc_extern && pedantic) + if (RIDBIT_SETP (RID_EXTERN, specbits) && pedantic) { - pedwarn ("cannot explicitly declare member %q#D to have " - "extern linkage", - decl); - storage_class = sc_none; + pedwarn ("cannot explicitly declare member `%#D' to have extern linkage", + decl); + RIDBIT_RESET (RID_EXTERN, specbits); } } } + my_friendly_assert (!RIDBIT_SETP (RID_MUTABLE, specbits), 19990927); + /* Record `register' declaration for warnings on & and in case doing stupid register allocation. */ - if (storage_class == sc_register) + if (RIDBIT_SETP (RID_REGISTER, specbits)) DECL_REGISTER (decl) = 1; - else if (storage_class == sc_extern) + + if (RIDBIT_SETP (RID_EXTERN, specbits)) DECL_THIS_EXTERN (decl) = 1; - else if (storage_class == sc_static) + + if (RIDBIT_SETP (RID_STATIC, specbits)) DECL_THIS_STATIC (decl) = 1; /* Record constancy and volatility. There's no need to do this when processing a template; we'll do this for the instantiated declaration based on the type of DECL. */ if (!processing_template_decl) - cp_apply_type_quals_to_decl (type_quals, decl); + c_apply_type_quals_to_decl (type_quals, decl); return decl; } @@ -8712,18 +8580,14 @@ require_complete_types_for_parms (tree parms) { for (; parms; parms = TREE_CHAIN (parms)) { - if (dependent_type_p (TREE_TYPE (parms))) - continue; - if (!VOID_TYPE_P (TREE_TYPE (parms)) - && complete_type_or_else (TREE_TYPE (parms), parms)) + if (VOID_TYPE_P (TREE_TYPE (parms))) + /* grokparms will have already issued an error. */ + TREE_TYPE (parms) = error_mark_node; + else if (complete_type_or_else (TREE_TYPE (parms), parms)) { - relayout_decl (parms); + layout_decl (parms, 0); DECL_ARG_TYPE (parms) = type_passed_as (TREE_TYPE (parms)); } - else - /* grokparms or complete_type_or_else will have already issued - an error. */ - TREE_TYPE (parms) = error_mark_node; } } @@ -8760,18 +8624,14 @@ nonstatic_local_decl_p (tree t) function. */ static tree -local_variable_p_walkfn (tree *tp, int *walk_subtrees, - void *data ATTRIBUTE_UNUSED) +local_variable_p_walkfn (tree* tp, + int* walk_subtrees ATTRIBUTE_UNUSED , + void* data ATTRIBUTE_UNUSED ) { - if (local_variable_p (*tp) && !DECL_ARTIFICIAL (*tp)) - return *tp; - else if (TYPE_P (*tp)) - *walk_subtrees = 0; - - return NULL_TREE; + return ((local_variable_p (*tp) && !DECL_ARTIFICIAL (*tp)) + ? *tp : NULL_TREE); } - /* Check that ARG, which is a default-argument expression for a parameter DECL, is valid. Returns ARG, or ERROR_MARK_NODE, if something goes wrong. DECL may also be a _TYPE node, rather than a @@ -8789,6 +8649,13 @@ check_default_argument (tree decl, tree arg) deal with it after the class is complete. */ return arg; + if (processing_template_decl || uses_template_parms (arg)) + /* We don't do anything checking until instantiation-time. Note + that there may be uninstantiated arguments even for an + instantiated function, since default arguments are not + instantiated until they are needed. */ + return arg; + if (TYPE_P (decl)) { decl_type = decl; @@ -8810,14 +8677,14 @@ check_default_argument (tree decl, tree arg) A default argument expression is implicitly converted to the parameter type. */ if (!TREE_TYPE (arg) - || !can_convert_arg (decl_type, TREE_TYPE (arg), arg, LOOKUP_NORMAL)) + || !can_convert_arg (decl_type, TREE_TYPE (arg), arg)) { if (decl) - error ("default argument for %q#D has type %qT", - decl, TREE_TYPE (arg)); + error ("default argument for `%#D' has type `%T'", + decl, TREE_TYPE (arg)); else - error ("default argument for parameter of type %qT has type %qT", - decl_type, TREE_TYPE (arg)); + error ("default argument for parameter of type `%T' has type `%T'", + decl_type, TREE_TYPE (arg)); return error_mark_node; } @@ -8833,7 +8700,8 @@ check_default_argument (tree decl, tree arg) NULL); if (var) { - error ("default argument %qE uses local variable %qD", arg, var); + error ("default argument `%E' uses local variable `%D'", + arg, var); return error_mark_node; } @@ -8845,55 +8713,69 @@ check_default_argument (tree decl, tree arg) Given the list of things declared inside the parens, return a list of types. - If this parameter does not end with an ellipsis, we append - void_list_node. + We determine whether ellipsis parms are used by PARMLIST_ELLIPSIS_P + flag. If unset, we append void_list_node. A parmlist declared + as `(void)' is accepted as the empty parmlist. *PARMS is set to the chain of PARM_DECLs created. */ static tree -grokparms (cp_parameter_declarator *first_parm, tree *parms) +grokparms (tree first_parm, tree *parms) { tree result = NULL_TREE; tree decls = NULL_TREE; - int ellipsis = !first_parm || first_parm->ellipsis_p; - cp_parameter_declarator *parm; + int ellipsis = !first_parm || PARMLIST_ELLIPSIS_P (first_parm); + tree parm, chain; int any_error = 0; - for (parm = first_parm; parm != NULL; parm = parm->next) + my_friendly_assert (!first_parm || TREE_PARMLIST (first_parm), 20001115); + + for (parm = first_parm; parm != NULL_TREE; parm = chain) { tree type = NULL_TREE; - tree init = parm->default_argument; - tree attrs; - tree decl; + tree decl = TREE_VALUE (parm); + tree init = TREE_PURPOSE (parm); + tree specs, attrs; - if (parm == no_parameters) - break; + chain = TREE_CHAIN (parm); + /* @@ weak defense against parse errors. */ + if (TREE_CODE (decl) != VOID_TYPE + && TREE_CODE (decl) != TREE_LIST) + { + /* Give various messages as the need arises. */ + if (TREE_CODE (decl) == STRING_CST) + error ("invalid string constant `%E'", decl); + else if (TREE_CODE (decl) == INTEGER_CST) + error ("invalid integer constant in parameter list, did you forget to give parameter name?"); + continue; + } + + if (parm == void_list_node) + break; - attrs = parm->decl_specifiers.attributes; - parm->decl_specifiers.attributes = NULL_TREE; - decl = grokdeclarator (parm->declarator, &parm->decl_specifiers, + split_specs_attrs (TREE_PURPOSE (decl), &specs, &attrs); + decl = grokdeclarator (TREE_VALUE (decl), specs, PARM, init != NULL_TREE, &attrs); if (! decl || TREE_TYPE (decl) == error_mark_node) - continue; + continue; if (attrs) cplus_decl_attributes (&decl, attrs, 0); type = TREE_TYPE (decl); if (VOID_TYPE_P (type)) - { - if (same_type_p (type, void_type_node) - && DECL_SELF_REFERENCE_P (type) - && !DECL_NAME (decl) && !result && !parm->next && !ellipsis) - /* this is a parmlist of `(void)', which is ok. */ - break; - cxx_incomplete_type_error (decl, type); + { + if (same_type_p (type, void_type_node) + && !DECL_NAME (decl) && !result && !chain && !ellipsis) + /* this is a parmlist of `(void)', which is ok. */ + break; + cxx_incomplete_type_error (decl, type); /* It's not a good idea to actually create parameters of type `void'; other parts of the compiler assume that a void type terminates the parameter list. */ type = error_mark_node; TREE_TYPE (decl) = error_mark_node; - } + } if (type != error_mark_node) { @@ -8902,7 +8784,7 @@ grokparms (cp_parameter_declarator *first_parm, tree *parms) type = cp_build_qualified_type (type, 0); if (TREE_CODE (type) == METHOD_TYPE) { - error ("parameter %qD invalidly declared method type", decl); + error ("parameter `%D' invalidly declared method type", decl); type = build_pointer_type (type); TREE_TYPE (decl) = type; } @@ -8915,26 +8797,25 @@ grokparms (cp_parameter_declarator *first_parm, tree *parms) tree t = TREE_TYPE (type); int ptr = TYPE_PTR_P (type); - while (1) - { - if (TYPE_PTR_P (t)) - ptr = 1; - else if (TREE_CODE (t) != ARRAY_TYPE) - break; - else if (!TYPE_DOMAIN (t)) - break; - t = TREE_TYPE (t); - } + while (1) + { + if (TYPE_PTR_P (t)) + ptr = 1; + else if (TREE_CODE (t) != ARRAY_TYPE) + break; + else if (!TYPE_DOMAIN (t)) + break; + t = TREE_TYPE (t); + } if (TREE_CODE (t) == ARRAY_TYPE) - error ("parameter %qD includes %s to array of unknown " - "bound %qT", - decl, ptr ? "pointer" : "reference", t); + error ("parameter `%D' includes %s to array of unknown bound `%T'", + decl, ptr ? "pointer" : "reference", t); } - if (any_error) - init = NULL_TREE; - else if (init && !processing_template_decl) + if (!any_error && init) init = check_default_argument (decl, init); + else + init = NULL_TREE; } TREE_CHAIN (decl) = decls; @@ -8975,25 +8856,21 @@ copy_fn_p (tree d) tree args; tree arg_type; int result = 1; + + my_friendly_assert (DECL_FUNCTION_MEMBER_P (d), 20011208); - gcc_assert (DECL_FUNCTION_MEMBER_P (d)); - - if (TREE_CODE (d) == TEMPLATE_DECL - || (DECL_TEMPLATE_INFO (d) - && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (d)))) + if (DECL_TEMPLATE_INFO (d) && is_member_template (DECL_TI_TEMPLATE (d))) /* Instantiations of template member functions are never copy functions. Note that member functions of templated classes are represented as template functions internally, and we must accept those as copy functions. */ return 0; - + args = FUNCTION_FIRST_USER_PARMTYPE (d); if (!args) return 0; arg_type = TREE_VALUE (args); - if (arg_type == error_mark_node) - return 0; if (TYPE_MAIN_VARIANT (arg_type) == DECL_CONTEXT (d)) { @@ -9008,7 +8885,7 @@ copy_fn_p (tree d) } else return 0; - + args = TREE_CHAIN (args); if (args && args != void_list_node && !TREE_PURPOSE (args)) @@ -9022,49 +8899,45 @@ copy_fn_p (tree d) void grok_special_member_properties (tree decl) { - tree class_type; - - if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) - return; - - class_type = DECL_CONTEXT (decl); - if (DECL_CONSTRUCTOR_P (decl)) + if (!DECL_NONSTATIC_MEMBER_FUNCTION_P(decl)) + ; /* Not special. */ + else if (DECL_CONSTRUCTOR_P (decl)) { int ctor = copy_fn_p (decl); - - TYPE_HAS_CONSTRUCTOR (class_type) = 1; - + if (ctor > 0) { /* [class.copy] - - A non-template constructor for class X is a copy - constructor if its first parameter is of type X&, const - X&, volatile X& or const volatile X&, and either there - are no other parameters or else all other parameters have - default arguments. */ - TYPE_HAS_INIT_REF (class_type) = 1; + + A non-template constructor for class X is a copy + constructor if its first parameter is of type X&, const + X&, volatile X& or const volatile X&, and either there + are no other parameters or else all other parameters have + default arguments. */ + TYPE_HAS_INIT_REF (DECL_CONTEXT (decl)) = 1; if (ctor > 1) - TYPE_HAS_CONST_INIT_REF (class_type) = 1; + TYPE_HAS_CONST_INIT_REF (DECL_CONTEXT (decl)) = 1; } else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl))) - TYPE_HAS_DEFAULT_CONSTRUCTOR (class_type) = 1; + TYPE_HAS_DEFAULT_CONSTRUCTOR (DECL_CONTEXT (decl)) = 1; } else if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR) { /* [class.copy] - - A non-template assignment operator for class X is a copy - assignment operator if its parameter is of type X, X&, const - X&, volatile X& or const volatile X&. */ - + + A non-template assignment operator for class X is a copy + assignment operator if its parameter is of type X, X&, const + X&, volatile X& or const volatile X&. */ + int assop = copy_fn_p (decl); - + if (assop) { - TYPE_HAS_ASSIGN_REF (class_type) = 1; + TYPE_HAS_ASSIGN_REF (DECL_CONTEXT (decl)) = 1; if (assop != 1) - TYPE_HAS_CONST_ASSIGN_REF (class_type) = 1; + TYPE_HAS_CONST_ASSIGN_REF (DECL_CONTEXT (decl)) = 1; + if (DECL_PURE_VIRTUAL_P (decl)) + TYPE_HAS_ABSTRACT_ASSIGN_REF (DECL_CONTEXT (decl)) = 1; } } } @@ -9080,25 +8953,26 @@ grok_ctor_properties (tree ctype, tree decl) if (ctor_parm < 0) { /* [class.copy] - - A declaration of a constructor for a class X is ill-formed if - its first parameter is of type (optionally cv-qualified) X - and either there are no other parameters or else all other - parameters have default arguments. - - We *don't* complain about member template instantiations that - have this form, though; they can occur as we try to decide - what constructor to use during overload resolution. Since - overload resolution will never prefer such a constructor to - the non-template copy constructor (which is either explicitly - or implicitly defined), there's no need to worry about their - existence. Theoretically, they should never even be - instantiated, but that's hard to forestall. */ - error ("invalid constructor; you probably meant %<%T (const %T&)%>", + + A declaration of a constructor for a class X is ill-formed if + its first parameter is of type (optionally cv-qualified) X + and either there are no other parameters or else all other + parameters have default arguments. + + We *don't* complain about member template instantiations that + have this form, though; they can occur as we try to decide + what constructor to use during overload resolution. Since + overload resolution will never prefer such a constructor to + the non-template copy constructor (which is either explicitly + or implicitly defined), there's no need to worry about their + existence. Theoretically, they should never even be + instantiated, but that's hard to forestall. */ + error ("invalid constructor; you probably meant `%T (const %T&)'", ctype, ctype); + SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype); return 0; } - + return 1; } @@ -9109,7 +8983,7 @@ ambi_op_p (enum tree_code code) { return (code == INDIRECT_REF || code == ADDR_EXPR - || code == UNARY_PLUS_EXPR + || code == CONVERT_EXPR || code == NEGATE_EXPR || code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR); @@ -9126,7 +9000,8 @@ unary_op_p (enum tree_code code) || code == TYPE_EXPR); } -/* DECL is a declaration for an overloaded operator. If COMPLAIN is true, +/* DECL is a declaration for an overloaded operator. Returns true if + the declaration is valid; false otherwise. If COMPLAIN is true, errors are issued for invalid declarations. */ bool @@ -9139,9 +9014,13 @@ grok_op_properties (tree decl, bool complain) enum tree_code operator_code; int arity; bool ellipsis_p; + bool ok; tree class_type; - /* Count the number of arguments and check for ellipsis. */ + /* Assume that the declaration is valid. */ + ok = true; + + /* Count the number of arguments. and check for ellipsis */ for (argtype = argtypes, arity = 0; argtype && argtype != void_list_node; argtype = TREE_CHAIN (argtype)) @@ -9151,7 +9030,7 @@ grok_op_properties (tree decl, bool complain) class_type = DECL_CONTEXT (decl); if (class_type && !CLASS_TYPE_P (class_type)) class_type = NULL_TREE; - + if (DECL_CONV_FN_P (decl)) operator_code = TYPE_EXPR; else @@ -9173,10 +9052,10 @@ grok_op_properties (tree decl, bool complain) #include "operators.def" #undef DEF_OPERATOR - gcc_unreachable (); + abort (); } while (0); - gcc_assert (operator_code != LAST_CPLUS_TREE_CODE); + my_friendly_assert (operator_code != LAST_CPLUS_TREE_CODE, 20000526); SET_OVERLOADED_OPERATOR_CODE (decl, operator_code); if (class_type) @@ -9202,31 +9081,6 @@ grok_op_properties (tree decl, bool complain) break; } - /* [basic.std.dynamic.allocation]/1: - - A program is ill-formed if an allocation function is declared - in a namespace scope other than global scope or declared static - in global scope. - - The same also holds true for deallocation functions. */ - if (operator_code == NEW_EXPR || operator_code == VEC_NEW_EXPR - || operator_code == DELETE_EXPR || operator_code == VEC_DELETE_EXPR) - { - if (DECL_NAMESPACE_SCOPE_P (decl)) - { - if (CP_DECL_CONTEXT (decl) != global_namespace) - { - error ("%qD may not be declared within a namespace", decl); - return false; - } - else if (!TREE_PUBLIC (decl)) - { - error ("%qD may not be declared as static", decl); - return false; - } - } - } - if (operator_code == NEW_EXPR || operator_code == VEC_NEW_EXPR) TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl)); else if (operator_code == DELETE_EXPR || operator_code == VEC_DELETE_EXPR) @@ -9243,27 +9097,17 @@ grok_op_properties (tree decl, bool complain) || operator_code == COMPONENT_REF || operator_code == ARRAY_REF || operator_code == NOP_EXPR) - { - error ("%qD must be a nonstatic member function", decl); - return false; - } + error ("`%D' must be a nonstatic member function", decl); else { tree p; if (DECL_STATIC_FUNCTION_P (decl)) - { - error ("%qD must be either a non-static member " - "function or a non-member function", decl); - return false; - } + error ("`%D' must be either a non-static member function or a non-member function", decl); for (p = argtypes; p && p != void_list_node; p = TREE_CHAIN (p)) { tree arg = non_reference (TREE_VALUE (p)); - if (arg == error_mark_node) - return false; - /* IS_AGGR_TYPE, rather than CLASS_TYPE_P, is used because these checks are performed even on template functions. */ @@ -9273,10 +9117,13 @@ grok_op_properties (tree decl, bool complain) if (!p || p == void_list_node) { - if (complain) - error ("%qD must have an argument of class or " - "enumerated type", decl); - return false; + if (!complain) + return false; + + error ("`%D' must have an argument of class or " + "enumerated type", + decl); + ok = false; } } } @@ -9284,10 +9131,10 @@ grok_op_properties (tree decl, bool complain) /* There are no restrictions on the arguments to an overloaded "operator ()". */ if (operator_code == CALL_EXPR) - return true; + return ok; /* Warn about conversion operators that will never be used. */ - if (IDENTIFIER_TYPENAME_P (name) + if (IDENTIFIER_TYPENAME_P (name) && ! DECL_TEMPLATE_INFO (decl) && warn_conversion /* Warn only declaring the function; there is no need to @@ -9297,10 +9144,10 @@ grok_op_properties (tree decl, bool complain) tree t = TREE_TYPE (name); int ref = (TREE_CODE (t) == REFERENCE_TYPE); const char *what = 0; - + if (ref) t = TYPE_MAIN_VARIANT (TREE_TYPE (t)); - + if (TREE_CODE (t) == VOID_TYPE) what = "void"; else if (class_type) @@ -9315,8 +9162,7 @@ grok_op_properties (tree decl, bool complain) } if (what) - warning (OPT_Wconversion, "conversion to %s%s will never use a type " - "conversion operator", + warning ("conversion to %s%s will never use a type conversion operator", ref ? "a reference to " : "", what); } @@ -9324,13 +9170,9 @@ grok_op_properties (tree decl, bool complain) { /* 13.4.0.3 */ error ("ISO C++ prohibits overloading operator ?:"); - return false; } else if (ellipsis_p) - { - error ("%qD must not have variable number of arguments", decl); - return false; - } + error ("`%D' must not have variable number of arguments", decl); else if (ambi_op_p (operator_code)) { if (arity == 1) @@ -9351,7 +9193,7 @@ grok_op_properties (tree decl, bool complain) operator_code = BIT_AND_EXPR; break; - case UNARY_PLUS_EXPR: + case CONVERT_EXPR: operator_code = PLUS_EXPR; break; @@ -9368,7 +9210,7 @@ grok_op_properties (tree decl, bool complain) break; default: - gcc_unreachable (); + abort (); } SET_OVERLOADED_OPERATOR_CODE (decl, operator_code); @@ -9379,21 +9221,20 @@ grok_op_properties (tree decl, bool complain) && ! same_type_p (TREE_VALUE (TREE_CHAIN (argtypes)), integer_type_node)) { if (methodp) - error ("postfix %qD must take %<int%> as its argument", - decl); + error ("postfix `%D' must take `int' as its argument", + decl); else - error ("postfix %qD must take %<int%> as its second " - "argument", decl); - return false; + error + ("postfix `%D' must take `int' as its second argument", + decl); } } else { if (methodp) - error ("%qD must take either zero or one argument", decl); + error ("`%D' must take either zero or one argument", decl); else - error ("%qD must take either one or two arguments", decl); - return false; + error ("`%D' must take either one or two arguments", decl); } /* More Effective C++ rule 6. */ @@ -9414,13 +9255,13 @@ grok_op_properties (tree decl, bool complain) if (TREE_CODE (ret) != REFERENCE_TYPE || !same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (ret)), arg)) - warning (OPT_Weffc__, "prefix %qD should return %qT", decl, - build_reference_type (arg)); + warning ("prefix `%D' should return `%T'", decl, + build_reference_type (arg)); } else { if (!same_type_p (TYPE_MAIN_VARIANT (ret), arg)) - warning (OPT_Weffc__, "postfix %qD should return %qT", decl, arg); + warning ("postfix `%D' should return `%T'", decl, arg); } } } @@ -9429,10 +9270,9 @@ grok_op_properties (tree decl, bool complain) if (arity != 1) { if (methodp) - error ("%qD must take %<void%>", decl); + error ("`%D' must take `void'", decl); else - error ("%qD must take exactly one argument", decl); - return false; + error ("`%D' must take exactly one argument", decl); } } else /* if (binary_op_p (operator_code)) */ @@ -9440,10 +9280,9 @@ grok_op_properties (tree decl, bool complain) if (arity != 2) { if (methodp) - error ("%qD must take exactly one argument", decl); + error ("`%D' must take exactly one argument", decl); else - error ("%qD must take exactly two arguments", decl); - return false; + error ("`%D' must take exactly two arguments", decl); } /* More Effective C++ rule 7. */ @@ -9451,8 +9290,8 @@ grok_op_properties (tree decl, bool complain) && (operator_code == TRUTH_ANDIF_EXPR || operator_code == TRUTH_ORIF_EXPR || operator_code == COMPOUND_EXPR)) - warning (OPT_Weffc__, "user-defined %qD always evaluates both arguments", - decl); + warning ("user-defined `%D' always evaluates both arguments", + decl); } /* Effective C++ rule 23. */ @@ -9465,32 +9304,29 @@ grok_op_properties (tree decl, bool complain) || operator_code == MULT_EXPR || operator_code == TRUNC_MOD_EXPR) && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE) - warning (OPT_Weffc__, "%qD should return by value", decl); + warning ("`%D' should return by value", decl); /* [over.oper]/8 */ for (; argtypes && argtypes != void_list_node; - argtypes = TREE_CHAIN (argtypes)) - if (TREE_PURPOSE (argtypes)) - { - TREE_PURPOSE (argtypes) = NULL_TREE; - if (operator_code == POSTINCREMENT_EXPR + argtypes = TREE_CHAIN (argtypes)) + if (TREE_PURPOSE (argtypes)) + { + TREE_PURPOSE (argtypes) = NULL_TREE; + if (operator_code == POSTINCREMENT_EXPR || operator_code == POSTDECREMENT_EXPR) - { - if (pedantic) - pedwarn ("%qD cannot have default arguments", decl); - } - else - { - error ("%qD cannot have default arguments", decl); - return false; - } - } + { + if (pedantic) + pedwarn ("`%D' cannot have default arguments", decl); + } + else + error ("`%D' cannot have default arguments", decl); + } + } - return true; + + return ok; } -/* Return a string giving the keyword associate with CODE. */ - static const char * tag_name (enum tag_types code) { @@ -9507,7 +9343,7 @@ tag_name (enum tag_types code) case typename_type: return "typename"; default: - gcc_unreachable (); + abort (); } } @@ -9535,15 +9371,7 @@ check_elaborated_type_specifier (enum tag_types tag_code, type = TREE_TYPE (decl); - /* Check TEMPLATE_TYPE_PARM first because DECL_IMPLICIT_TYPEDEF_P - is false for this case as well. */ - if (TREE_CODE (type) == TEMPLATE_TYPE_PARM) - { - error ("using template type parameter %qT after %qs", - type, tag_name (tag_code)); - return error_mark_node; - } - /* [dcl.type.elab] + /* [dcl.type.elab] If the identifier resolves to a typedef-name or a template type-parameter, the elaborated-type-specifier is ill-formed. @@ -9551,11 +9379,17 @@ check_elaborated_type_specifier (enum tag_types tag_code, In other words, the only legitimate declaration to use in the elaborated type specifier is the implicit typedef created when the type is declared. */ - else if (!DECL_IMPLICIT_TYPEDEF_P (decl) - && tag_code != typename_type) + if (!DECL_IMPLICIT_TYPEDEF_P (decl) + && tag_code != typename_type) + { + error ("using typedef-name `%D' after `%s'", decl, tag_name (tag_code)); + return IS_AGGR_TYPE (type) ? type : error_mark_node; + } + + if (TREE_CODE (type) == TEMPLATE_TYPE_PARM) { - error ("using typedef-name %qD after %qs", decl, tag_name (tag_code)); - error ("%q+D has a previous declaration here", decl); + error ("using template type parameter `%T' after `%s'", + type, tag_name (tag_code)); return error_mark_node; } else if (TREE_CODE (type) != RECORD_TYPE @@ -9563,15 +9397,13 @@ check_elaborated_type_specifier (enum tag_types tag_code, && tag_code != enum_type && tag_code != typename_type) { - error ("%qT referred to as %qs", type, tag_name (tag_code)); - error ("%q+T has a previous declaration here", type); + error ("`%T' referred to as `%s'", type, tag_name (tag_code)); return error_mark_node; } else if (TREE_CODE (type) != ENUMERAL_TYPE && tag_code == enum_type) { - error ("%qT referred to as enum", type); - error ("%q+T has a previous declaration here", type); + error ("`%T' referred to as enum", type); return error_mark_node; } else if (!allow_template_p @@ -9585,7 +9417,8 @@ check_elaborated_type_specifier (enum tag_types tag_code, void f(class C); // No template header here then the required template argument is missing. */ - error ("template argument required for %<%s %T%>", + + error ("template argument required for `%s %T'", tag_name (tag_code), DECL_NAME (CLASSTYPE_TI_TEMPLATE (type))); return error_mark_node; @@ -9594,103 +9427,31 @@ check_elaborated_type_specifier (enum tag_types tag_code, return type; } -/* Lookup NAME in elaborate type specifier in scope according to - SCOPE and issue diagnostics if necessary. - Return *_TYPE node upon success, NULL_TREE when the NAME is not - found, and ERROR_MARK_NODE for type error. */ - -static tree -lookup_and_check_tag (enum tag_types tag_code, tree name, - tag_scope scope, bool template_header_p) -{ - tree t; - tree decl; - if (scope == ts_global) - { - /* First try ordinary name lookup, ignoring hidden class name - injected via friend declaration. */ - decl = lookup_name_prefer_type (name, 2); - /* If that fails, the name will be placed in the smallest - non-class, non-function-prototype scope according to 3.3.1/5. - We may already have a hidden name declared as friend in this - scope. So lookup again but not ignoring hidden names. - If we find one, that name will be made visible rather than - creating a new tag. */ - if (!decl) - decl = lookup_type_scope (name, ts_within_enclosing_non_class); - } - else - decl = lookup_type_scope (name, scope); - - if (decl && DECL_CLASS_TEMPLATE_P (decl)) - decl = DECL_TEMPLATE_RESULT (decl); - - if (decl && TREE_CODE (decl) == TYPE_DECL) - { - /* Look for invalid nested type: - class C { - class C {}; - }; */ - if (scope == ts_current && DECL_SELF_REFERENCE_P (decl)) - { - error ("%qD has the same name as the class in which it is " - "declared", - decl); - return error_mark_node; - } - - /* Two cases we need to consider when deciding if a class - template is allowed as an elaborated type specifier: - 1. It is a self reference to its own class. - 2. It comes with a template header. - - For example: - - template <class T> class C { - class C *c1; // DECL_SELF_REFERENCE_P is true - class D; - }; - template <class U> class C; // template_header_p is true - template <class T> class C<T>::D { - class C *c2; // DECL_SELF_REFERENCE_P is true - }; */ - - t = check_elaborated_type_specifier (tag_code, - decl, - template_header_p - | DECL_SELF_REFERENCE_P (decl)); - return t; - } - else - return NULL_TREE; -} - /* Get the struct, enum or union (TAG_CODE says which) with tag NAME. Define the tag as a forward-reference if it is not defined. If a declaration is given, process it here, and report an error if multiple declarations are not identical. - SCOPE is TS_CURRENT when this is also a definition. Only look in + GLOBALIZE is false when this is also a definition. Only look in the current frame for the name (since C++ allows new names in any - scope.) It is TS_WITHIN_ENCLOSING_NON_CLASS if this is a friend - declaration. Only look beginning from the current scope outward up - till the nearest non-class scope. Otherwise it is TS_GLOBAL. + scope.) TEMPLATE_HEADER_P is true when this declaration is preceded by a set of template parameters. */ tree xref_tag (enum tag_types tag_code, tree name, - tag_scope scope, bool template_header_p) + bool globalize, bool template_header_p) { enum tree_code code; tree t; + struct cp_binding_level *b = current_binding_level; tree context = NULL_TREE; timevar_push (TV_NAME_LOOKUP); - gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); + my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 0); switch (tag_code) { @@ -9705,62 +9466,93 @@ xref_tag (enum tag_types tag_code, tree name, code = ENUMERAL_TYPE; break; default: - gcc_unreachable (); + abort (); } - /* In case of anonymous name, xref_tag is only called to - make type node and push name. Name lookup is not required. */ - if (ANON_AGGRNAME_P (name)) - t = NULL_TREE; + if (! globalize) + { + /* If we know we are defining this tag, only look it up in + this scope and don't try to find it as a type. */ + t = lookup_tag (code, name, b, 1); + } else - t = lookup_and_check_tag (tag_code, name, - scope, template_header_p); + { + tree decl = lookup_name (name, 2); - if (t == error_mark_node) - POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); + if (decl && DECL_CLASS_TEMPLATE_P (decl)) + decl = DECL_TEMPLATE_RESULT (decl); - if (scope != ts_current && t && current_class_type - && template_class_depth (current_class_type) - && template_header_p) - { - /* Since SCOPE is not TS_CURRENT, we are not looking at a - definition of this tag. Since, in addition, we are currently - processing a (member) template declaration of a template - class, we must be very careful; consider: + if (decl && TREE_CODE (decl) == TYPE_DECL) + { + /* Two cases we need to consider when deciding if a class + template is allowed as an elaborated type specifier: + 1. It is a self reference to its own class. + 2. It comes with a template header. + + For example: + + template <class T> class C { + class C *c1; // DECL_SELF_REFERENCE_P is true + class D; + }; + template <class U> class C; // template_header_p is true + template <class T> class C<T>::D { + class C *c2; // DECL_SELF_REFERENCE_P is true + }; */ + + t = check_elaborated_type_specifier (tag_code, + decl, + template_header_p + | DECL_SELF_REFERENCE_P (decl)); + if (t == error_mark_node) + POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); + } + else + t = NULL_TREE; - template <class X> - struct S1 + if (t && current_class_type + && template_class_depth (current_class_type) + && template_header_p) + { + /* Since GLOBALIZE is nonzero, we are not looking at a + definition of this tag. Since, in addition, we are currently + processing a (member) template declaration of a template + class, we must be very careful; consider: + + template <class X> + struct S1 - template <class U> - struct S2 - { template <class V> - friend struct S1; }; + template <class U> + struct S2 + { template <class V> + friend struct S1; }; - Here, the S2::S1 declaration should not be confused with the - outer declaration. In particular, the inner version should - have a template parameter of level 2, not level 1. This - would be particularly important if the member declaration - were instead: + Here, the S2::S1 declaration should not be confused with the + outer declaration. In particular, the inner version should + have a template parameter of level 2, not level 1. This + would be particularly important if the member declaration + were instead: - template <class V = U> friend struct S1; + template <class V = U> friend struct S1; - say, when we should tsubst into `U' when instantiating - S2. On the other hand, when presented with: + say, when we should tsubst into `U' when instantiating + S2. On the other hand, when presented with: - template <class T> - struct S1 { - template <class U> - struct S2 {}; - template <class U> - friend struct S2; - }; + template <class T> + struct S1 { + template <class U> + struct S2 {}; + template <class U> + friend struct S2; + }; - we must find the inner binding eventually. We - accomplish this by making sure that the new type we - create to represent this declaration has the right - TYPE_CONTEXT. */ - context = TYPE_CONTEXT (t); - t = NULL_TREE; + we must find the inner binding eventually. We + accomplish this by making sure that the new type we + create to represent this declaration has the right + TYPE_CONTEXT. */ + context = TYPE_CONTEXT (t); + t = NULL_TREE; + } } if (! t) @@ -9771,44 +9563,26 @@ xref_tag (enum tag_types tag_code, tree name, the forward-reference will be altered into a real type. */ if (code == ENUMERAL_TYPE) { - error ("use of enum %q#D without previous declaration", name); + error ("use of enum `%#D' without previous declaration", name); POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); } else { t = make_aggr_type (code); TYPE_CONTEXT (t) = context; - t = pushtag (name, t, scope); + pushtag (name, t, globalize); } } else { - if (template_header_p && IS_AGGR_TYPE (t)) - { - if (!redeclare_class_template (t, current_template_parms)) - POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); - } - else if (!processing_template_decl + if (!globalize && processing_template_decl && IS_AGGR_TYPE (t)) + redeclare_class_template (t, current_template_parms); + else if (!processing_template_decl && CLASS_TYPE_P (t) && CLASSTYPE_IS_TEMPLATE (t)) { - error ("redeclaration of %qT as a non-template", t); - error ("previous declaration %q+D", t); - POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); - } - - /* Make injected friend class visible. */ - if (scope != ts_within_enclosing_non_class - && hidden_name_p (TYPE_NAME (t))) - { - DECL_ANTICIPATED (TYPE_NAME (t)) = 0; - DECL_FRIEND_P (TYPE_NAME (t)) = 0; - - if (TYPE_TEMPLATE_INFO (t)) - { - DECL_ANTICIPATED (TYPE_TI_TEMPLATE (t)) = 0; - DECL_FRIEND_P (TYPE_TI_TEMPLATE (t)) = 0; - } + error ("redeclaration of `%T' as a non-template", t); + t = error_mark_node; } } @@ -9816,7 +9590,7 @@ xref_tag (enum tag_types tag_code, tree name, } tree -xref_tag_from_type (tree old, tree id, tag_scope scope) +xref_tag_from_type (tree old, tree id, int globalize) { enum tag_types tag_kind; @@ -9828,209 +9602,195 @@ xref_tag_from_type (tree old, tree id, tag_scope scope) if (id == NULL_TREE) id = TYPE_IDENTIFIER (old); - return xref_tag (tag_kind, id, scope, false); + return xref_tag (tag_kind, id, globalize, false); } -/* Create the binfo hierarchy for REF with (possibly NULL) base list - BASE_LIST. For each element on BASE_LIST the TREE_PURPOSE is an - access_* node, and the TREE_VALUE is the type of the base-class. - Non-NULL TREE_TYPE indicates virtual inheritance. - - Returns true if the binfo heirarchy was successfully created, - false if an error was detected. */ +/* REF is a type (named NAME), for which we have just seen some + baseclasses. BASE_LIST is a list of those baseclasses; the + TREE_PURPOSE is an access_* node, and the TREE_VALUE is the type of + the base-class. TREE_VIA_VIRTUAL indicates virtual + inheritance. CODE_TYPE_NODE indicates whether REF is a class, + struct, or union. */ -bool +void xref_basetypes (tree ref, tree base_list) { + /* In the declaration `A : X, Y, ... Z' we mark all the types + (A, X, Y, ..., Z) so we can check for duplicates. */ tree *basep; - tree binfo, base_binfo; - unsigned max_vbases = 0; /* Maximum direct & indirect virtual bases. */ - unsigned max_bases = 0; /* Maximum direct bases. */ + int i; - tree default_access; - tree igo_prev; /* Track Inheritance Graph Order. */ + enum tag_types tag_code; if (ref == error_mark_node) - return false; + return; - /* The base of a derived class is private by default, all others are - public. */ - default_access = (TREE_CODE (ref) == RECORD_TYPE - && CLASSTYPE_DECLARED_CLASS (ref) - ? access_private_node : access_public_node); + if (TREE_CODE (ref) == UNION_TYPE) + { + error ("derived union `%T' invalid", ref); + return; + } + + tag_code = (CLASSTYPE_DECLARED_CLASS (ref) ? class_type : record_type); /* First, make sure that any templates in base-classes are instantiated. This ensures that if we call ourselves recursively we do not get confused about which classes are marked and which are not. */ - basep = &base_list; - while (*basep) + basep = &base_list; + while (*basep) { tree basetype = TREE_VALUE (*basep); - if (!(processing_template_decl && uses_template_parms (basetype)) && !complete_type_or_else (basetype, NULL)) /* An incomplete type. Remove it from the list. */ *basep = TREE_CHAIN (*basep); else - { - max_bases++; - if (TREE_TYPE (*basep)) - max_vbases++; - if (CLASS_TYPE_P (basetype)) - max_vbases += VEC_length (tree, CLASSTYPE_VBASECLASSES (basetype)); - basep = &TREE_CHAIN (*basep); - } + basep = &TREE_CHAIN (*basep); } - TYPE_MARKED_P (ref) = 1; - - /* The binfo slot should be empty, unless this is an (ill-formed) - redefinition. */ - gcc_assert (!TYPE_BINFO (ref) || TYPE_SIZE (ref)); - gcc_assert (TYPE_MAIN_VARIANT (ref) == ref); - - binfo = make_tree_binfo (max_bases); - - TYPE_BINFO (ref) = binfo; - BINFO_OFFSET (binfo) = size_zero_node; - BINFO_TYPE (binfo) = ref; - - if (max_bases) + SET_CLASSTYPE_MARKED (ref); + i = list_length (base_list); + if (i) { - BINFO_BASE_ACCESSES (binfo) = VEC_alloc (tree, gc, max_bases); - /* An aggregate cannot have baseclasses. */ - CLASSTYPE_NON_AGGREGATE (ref) = 1; - - if (TREE_CODE (ref) == UNION_TYPE) - { - error ("derived union %qT invalid", ref); - return false; - } - } - - if (max_bases > 1) - { - if (TYPE_FOR_JAVA (ref)) - { - error ("Java class %qT cannot have multiple bases", ref); - return false; - } - } - - if (max_vbases) - { - CLASSTYPE_VBASECLASSES (ref) = VEC_alloc (tree, gc, max_vbases); - - if (TYPE_FOR_JAVA (ref)) - { - error ("Java class %qT cannot have virtual bases", ref); - return false; - } - } - - for (igo_prev = binfo; base_list; base_list = TREE_CHAIN (base_list)) - { - tree access = TREE_PURPOSE (base_list); - int via_virtual = TREE_TYPE (base_list) != NULL_TREE; - tree basetype = TREE_VALUE (base_list); - - if (access == access_default_node) - access = default_access; - - if (TREE_CODE (basetype) == TYPE_DECL) - basetype = TREE_TYPE (basetype); - if (TREE_CODE (basetype) != RECORD_TYPE - && TREE_CODE (basetype) != TYPENAME_TYPE - && TREE_CODE (basetype) != TEMPLATE_TYPE_PARM - && TREE_CODE (basetype) != BOUND_TEMPLATE_TEMPLATE_PARM) - { - error ("base type %qT fails to be a struct or class type", - basetype); - return false; - } - - if (TYPE_FOR_JAVA (basetype) && (current_lang_depth () == 0)) - TYPE_FOR_JAVA (ref) = 1; - - base_binfo = NULL_TREE; - if (CLASS_TYPE_P (basetype) && !dependent_type_p (basetype)) - { - base_binfo = TYPE_BINFO (basetype); - /* The original basetype could have been a typedef'd type. */ - basetype = BINFO_TYPE (base_binfo); - - /* Inherit flags from the base. */ - TYPE_HAS_NEW_OPERATOR (ref) - |= TYPE_HAS_NEW_OPERATOR (basetype); - TYPE_HAS_ARRAY_NEW_OPERATOR (ref) - |= TYPE_HAS_ARRAY_NEW_OPERATOR (basetype); - TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype); - TYPE_HAS_CONVERSION (ref) |= TYPE_HAS_CONVERSION (basetype); - CLASSTYPE_DIAMOND_SHAPED_P (ref) - |= CLASSTYPE_DIAMOND_SHAPED_P (basetype); - CLASSTYPE_REPEATED_BASE_P (ref) - |= CLASSTYPE_REPEATED_BASE_P (basetype); + tree binfo = TYPE_BINFO (ref); + tree binfos = make_tree_vec (i); + tree accesses = make_tree_vec (i); + + BINFO_BASETYPES (binfo) = binfos; + BINFO_BASEACCESSES (binfo) = accesses; + + for (i = 0; base_list; base_list = TREE_CHAIN (base_list)) + { + tree access = TREE_PURPOSE (base_list); + int via_virtual = TREE_VIA_VIRTUAL (base_list); + tree basetype = TREE_VALUE (base_list); + tree base_binfo; + + if (access == access_default_node) + /* The base of a derived struct is public by default. */ + access = (tag_code == class_type + ? access_private_node : access_public_node); + + if (basetype && TREE_CODE (basetype) == TYPE_DECL) + basetype = TREE_TYPE (basetype); + if (!basetype + || (TREE_CODE (basetype) != RECORD_TYPE + && TREE_CODE (basetype) != TYPENAME_TYPE + && TREE_CODE (basetype) != TEMPLATE_TYPE_PARM + && TREE_CODE (basetype) != BOUND_TEMPLATE_TEMPLATE_PARM)) + { + error ("base type `%T' fails to be a struct or class type", + basetype); + continue; + } + + if (CLASSTYPE_MARKED (basetype)) + { + if (basetype == ref) + error ("recursive type `%T' undefined", basetype); + else + error ("duplicate base type `%T' invalid", basetype); + continue; + } + + if (TYPE_FOR_JAVA (basetype) + && (current_lang_depth () == 0)) + TYPE_FOR_JAVA (ref) = 1; + + if (CLASS_TYPE_P (basetype)) + { + base_binfo = TYPE_BINFO (basetype); + /* This flag will be in the binfo of the base type, we must + clear it after copying the base binfos. */ + BINFO_DEPENDENT_BASE_P (base_binfo) + = dependent_type_p (basetype); + } + else + base_binfo = make_binfo (size_zero_node, basetype, + NULL_TREE, NULL_TREE); + + TREE_VEC_ELT (binfos, i) = base_binfo; + TREE_VEC_ELT (accesses, i) = access; + /* This flag will be in the binfo of the base type, we must + clear it after copying the base binfos. */ + TREE_VIA_VIRTUAL (base_binfo) = via_virtual; + + SET_CLASSTYPE_MARKED (basetype); + + /* We are free to modify these bits because they are meaningless + at top level, and BASETYPE is a top-level type. */ + if (via_virtual || TYPE_USES_VIRTUAL_BASECLASSES (basetype)) + { + TYPE_USES_VIRTUAL_BASECLASSES (ref) = 1; + /* Converting to a virtual base class requires looking + up the offset of the virtual base. */ + TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (ref) = 1; + } + + if (CLASS_TYPE_P (basetype)) + { + TYPE_HAS_NEW_OPERATOR (ref) + |= TYPE_HAS_NEW_OPERATOR (basetype); + TYPE_HAS_ARRAY_NEW_OPERATOR (ref) + |= TYPE_HAS_ARRAY_NEW_OPERATOR (basetype); + TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype); + /* If the base-class uses multiple inheritance, so do we. */ + TYPE_USES_MULTIPLE_INHERITANCE (ref) + |= TYPE_USES_MULTIPLE_INHERITANCE (basetype); + /* Likewise, if converting to a base of the base may require + code, then we may need to generate code to convert to a + base as well. */ + TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (ref) + |= TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype); + } + i++; } - - /* We must do this test after we've seen through a typedef - type. */ - if (TYPE_MARKED_P (basetype)) + if (i) + TREE_VEC_LENGTH (accesses) = TREE_VEC_LENGTH (binfos) = i; + else + BINFO_BASEACCESSES (binfo) = BINFO_BASETYPES (binfo) = NULL_TREE; + + if (i > 1) { - if (basetype == ref) - error ("recursive type %qT undefined", basetype); - else - error ("duplicate base type %qT invalid", basetype); - return false; + TYPE_USES_MULTIPLE_INHERITANCE (ref) = 1; + /* If there is more than one non-empty they cannot be at the same + address. */ + TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (ref) = 1; } - TYPE_MARKED_P (basetype) = 1; - - base_binfo = copy_binfo (base_binfo, basetype, ref, - &igo_prev, via_virtual); - if (!BINFO_INHERITANCE_CHAIN (base_binfo)) - BINFO_INHERITANCE_CHAIN (base_binfo) = binfo; - - BINFO_BASE_APPEND (binfo, base_binfo); - BINFO_BASE_ACCESS_APPEND (binfo, access); } + + /* Copy the base binfos, collect the virtual bases and set the + inheritance order chain. */ + copy_base_binfos (TYPE_BINFO (ref), ref, NULL_TREE); + CLASSTYPE_VBASECLASSES (ref) = nreverse (CLASSTYPE_VBASECLASSES (ref)); - if (VEC_space (tree, CLASSTYPE_VBASECLASSES (ref), 1)) - /* If we have space in the vbase vector, we must have shared at - least one of them, and are therefore diamond shaped. */ - CLASSTYPE_DIAMOND_SHAPED_P (ref) = 1; + if (TYPE_FOR_JAVA (ref)) + { + if (TYPE_USES_MULTIPLE_INHERITANCE (ref)) + error ("Java class '%T' cannot have multiple bases", ref); + if (CLASSTYPE_VBASECLASSES (ref)) + error ("Java class '%T' cannot have virtual bases", ref); + } /* Unmark all the types. */ - for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) - TYPE_MARKED_P (BINFO_TYPE (base_binfo)) = 0; - TYPE_MARKED_P (ref) = 0; - - /* Now see if we have a repeated base type. */ - if (!CLASSTYPE_REPEATED_BASE_P (ref)) + while (i--) { - for (base_binfo = binfo; base_binfo; - base_binfo = TREE_CHAIN (base_binfo)) + tree basetype = BINFO_TYPE (BINFO_BASETYPE (TYPE_BINFO (ref), i)); + + CLEAR_CLASSTYPE_MARKED (basetype); + if (CLASS_TYPE_P (basetype)) { - if (TYPE_MARKED_P (BINFO_TYPE (base_binfo))) - { - CLASSTYPE_REPEATED_BASE_P (ref) = 1; - break; - } - TYPE_MARKED_P (BINFO_TYPE (base_binfo)) = 1; + TREE_VIA_VIRTUAL (TYPE_BINFO (basetype)) = 0; + BINFO_DEPENDENT_BASE_P (TYPE_BINFO (basetype)) = 0; } - for (base_binfo = binfo; base_binfo; - base_binfo = TREE_CHAIN (base_binfo)) - if (TYPE_MARKED_P (BINFO_TYPE (base_binfo))) - TYPE_MARKED_P (BINFO_TYPE (base_binfo)) = 0; - else - break; } - - return true; + CLEAR_CLASSTYPE_MARKED (ref); } /* Begin compiling the definition of an enumeration type. - NAME is its name. + NAME is its name (or null if anonymous). Returns the type object, as yet incomplete. Also records info about it so that build_enumerator may be used to declare the individual values as they are read. */ @@ -10038,34 +9798,27 @@ xref_basetypes (tree ref, tree base_list) tree start_enum (tree name) { - tree enumtype; - - gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); + tree enumtype = NULL_TREE; + struct cp_binding_level *b = current_binding_level; /* If this is the real definition for a previous forward reference, fill in the contents in the same object that used to be the forward reference. */ - enumtype = lookup_and_check_tag (enum_type, name, - /*tag_scope=*/ts_current, - /*template_header_p=*/false); + if (name != NULL_TREE) + enumtype = lookup_tag (ENUMERAL_TYPE, name, b, 1); if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE) { - error ("multiple definition of %q#T", enumtype); + error ("multiple definition of `%#T'", enumtype); error ("%Jprevious definition here", TYPE_MAIN_DECL (enumtype)); /* Clear out TYPE_VALUES, and start again. */ TYPE_VALUES (enumtype) = NULL_TREE; } else { - /* In case of error, make a dummy enum to allow parsing to - continue. */ - if (enumtype == error_mark_node) - name = make_anon_name (); - enumtype = make_node (ENUMERAL_TYPE); - enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + pushtag (name, enumtype, 0); } return enumtype; @@ -10085,9 +9838,8 @@ finish_enum (tree enumtype) tree maxnode; tree t; bool unsignedp; - bool use_short_enum; int lowprec; - int highprec; + int highprec; int precision; integer_type_kind itk; tree underlying_type = NULL_TREE; @@ -10101,8 +9853,8 @@ finish_enum (tree enumtype) works. */ if (processing_template_decl) { - for (values = TYPE_VALUES (enumtype); - values; + for (values = TYPE_VALUES (enumtype); + values; values = TREE_CHAIN (values)) TREE_TYPE (TREE_VALUE (values)) = enumtype; if (at_function_scope_p ()) @@ -10115,8 +9867,8 @@ finish_enum (tree enumtype) { minnode = maxnode = NULL_TREE; - for (values = TYPE_VALUES (enumtype); - values; + for (values = TYPE_VALUES (enumtype); + values; values = TREE_CHAIN (values)) { decl = TREE_VALUE (values); @@ -10129,8 +9881,6 @@ finish_enum (tree enumtype) /* Update the minimum and maximum values, if appropriate. */ value = DECL_INITIAL (decl); - if (value == error_mark_node) - value = integer_zero_node; /* Figure out what the minimum and maximum values of the enumerators are. */ if (!minnode) @@ -10139,6 +9889,16 @@ finish_enum (tree enumtype) maxnode = value; else if (tree_int_cst_lt (value, minnode)) minnode = value; + + /* Set the TREE_TYPE for the values as well. That's so that when + we call decl_constant_value we get an entity of the right type + (but with the constant value). But first make a copy so we + don't clobber shared INTEGER_CSTs. */ + if (TREE_TYPE (value) != enumtype) + { + value = DECL_INITIAL (decl) = copy_node (value); + TREE_TYPE (value) = enumtype; + } } } else @@ -10166,24 +9926,18 @@ finish_enum (tree enumtype) enumeration. It is implementation-defined which integral type is used as the underlying type for an enumeration except that the underlying type shall not be larger than int unless the value of - an enumerator cannot fit in an int or unsigned int. + an enumerator cannot fit in an int or unsigned int. We use "int" or an "unsigned int" as the underlying type, even if a smaller integral type would work, unless the user has - explicitly requested that we use the smallest possible type. The - user can request that for all enumerations with a command line - flag, or for just one enumeration with an attribute. */ - - use_short_enum = flag_short_enums - || lookup_attribute ("packed", TYPE_ATTRIBUTES (enumtype)); - - for (itk = (use_short_enum ? itk_char : itk_int); - itk != itk_none; + explicitly requested that we use the smallest possible type. */ + for (itk = (flag_short_enums ? itk_char : itk_int); + itk != itk_none; itk++) { underlying_type = integer_types[itk]; if (TYPE_PRECISION (underlying_type) >= precision - && TYPE_UNSIGNED (underlying_type) == unsignedp) + && TREE_UNSIGNED (underlying_type) == unsignedp) break; } if (itk == itk_none) @@ -10193,12 +9947,12 @@ finish_enum (tree enumtype) IF no integral type can represent all the enumerator values, the enumeration is ill-formed. */ error ("no integral type can represent all of the enumerator values " - "for %qT", enumtype); + "for `%T'", enumtype); precision = TYPE_PRECISION (long_long_integer_type_node); underlying_type = integer_types[itk_unsigned_long_long]; } - /* Compute the minium and maximum values for the type. + /* Compute the minium and maximum values for the type. [dcl.enum] @@ -10212,13 +9966,13 @@ finish_enum (tree enumtype) narrower than their underlying type are suitably zero or sign extended to fill their mode. g++ doesn't make these guarantees. Until the middle-end can represent such paradoxical types, we - set the TYPE_PRECISION to the width of the underlying type. */ + set the TYPE_PRECISON to the width of the underlying type. */ TYPE_PRECISION (enumtype) = TYPE_PRECISION (underlying_type); set_min_and_max_values_for_integral_type (enumtype, precision, unsignedp); /* [dcl.enum] - + The value of sizeof() applied to an enumeration type, an object of an enumeration type, or an enumerator, is the value of sizeof() applied to the underlying type. */ @@ -10227,24 +9981,15 @@ finish_enum (tree enumtype) TYPE_MODE (enumtype) = TYPE_MODE (underlying_type); TYPE_ALIGN (enumtype) = TYPE_ALIGN (underlying_type); TYPE_USER_ALIGN (enumtype) = TYPE_USER_ALIGN (underlying_type); - TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (underlying_type); + TREE_UNSIGNED (enumtype) = TREE_UNSIGNED (underlying_type); /* Convert each of the enumerators to the type of the underlying type of the enumeration. */ for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values)) { - location_t saved_location; - decl = TREE_VALUE (values); - saved_location = input_location; - input_location = DECL_SOURCE_LOCATION (decl); value = perform_implicit_conversion (underlying_type, DECL_INITIAL (decl)); - input_location = saved_location; - - /* Do not clobber shared ints. */ - value = copy_node (value); - TREE_TYPE (value) = enumtype; DECL_INITIAL (decl) = value; TREE_VALUE (values) = value; @@ -10262,7 +10007,7 @@ finish_enum (tree enumtype) TYPE_PRECISION (t) = TYPE_PRECISION (enumtype); TYPE_ALIGN (t) = TYPE_ALIGN (enumtype); TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (enumtype); - TYPE_UNSIGNED (t) = TYPE_UNSIGNED (enumtype); + TREE_UNSIGNED (t) = TREE_UNSIGNED (enumtype); } /* Finish debugging output for this type. */ @@ -10280,11 +10025,6 @@ build_enumerator (tree name, tree value, tree enumtype) tree context; tree type; - /* If the VALUE was erroneous, pretend it wasn't there; that will - result in the enum being assigned the next value in sequence. */ - if (value == error_mark_node) - value = NULL_TREE; - /* Remove no-op casts from the value. */ if (value) STRIP_TYPE_NOPS (value); @@ -10294,7 +10034,7 @@ build_enumerator (tree name, tree value, tree enumtype) /* Validate and default VALUE. */ if (value != NULL_TREE) { - value = integral_constant_value (value); + value = decl_constant_value (value); if (TREE_CODE (value) == INTEGER_CST) { @@ -10303,7 +10043,7 @@ build_enumerator (tree name, tree value, tree enumtype) } else { - error ("enumerator value for %qD not integer constant", name); + error ("enumerator value for `%D' not integer constant", name); value = NULL_TREE; } } @@ -10311,29 +10051,19 @@ build_enumerator (tree name, tree value, tree enumtype) /* Default based on previous value. */ if (value == NULL_TREE) { + tree prev_value; + if (TYPE_VALUES (enumtype)) { - HOST_WIDE_INT hi; - unsigned HOST_WIDE_INT lo; - tree prev_value; - bool overflowed; - - /* The next value is the previous value plus one. We can - safely assume that the previous value is an INTEGER_CST. - add_double doesn't know the type of the target expression, - so we must check with int_fits_type_p as well. */ + /* The next value is the previous value ... */ prev_value = DECL_INITIAL (TREE_VALUE (TYPE_VALUES (enumtype))); - overflowed = add_double (TREE_INT_CST_LOW (prev_value), - TREE_INT_CST_HIGH (prev_value), - 1, 0, &lo, &hi); - value = build_int_cst_wide (TREE_TYPE (prev_value), lo, hi); - overflowed |= !int_fits_type_p (value, TREE_TYPE (prev_value)); + /* ... plus one. */ + value = cp_build_binary_op (PLUS_EXPR, + prev_value, + integer_one_node); - if (overflowed) - { - error ("overflow in enumeration values at %qD", name); - value = error_mark_node; - } + if (tree_int_cst_lt (value, prev_value)) + error ("overflow in enumeration values at `%D'", name); } else value = integer_zero_node; @@ -10345,6 +10075,8 @@ build_enumerator (tree name, tree value, tree enumtype) /* C++ associates enums with global, function, or class declarations. */ context = current_scope (); + if (!context) + context = current_namespace; /* Build the actual enumeration constant. Note that the enumeration constants have the type of their initializers until the @@ -10371,9 +10103,7 @@ build_enumerator (tree name, tree value, tree enumtype) decl = build_decl (CONST_DECL, name, type); DECL_CONTEXT (decl) = FROB_CONTEXT (context); - TREE_CONSTANT (decl) = 1; - TREE_INVARIANT (decl) = 1; - TREE_READONLY (decl) = 1; + TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1; DECL_INITIAL (decl) = value; if (context && context == current_class_type) @@ -10400,24 +10130,27 @@ check_function_type (tree decl, tree current_function_parms) /* In a function definition, arg types must be complete. */ require_complete_types_for_parms (current_function_parms); - if (dependent_type_p (return_type)) - return; if (!COMPLETE_OR_VOID_TYPE_P (return_type)) { - tree args = TYPE_ARG_TYPES (fntype); - - error ("return type %q#T is incomplete", return_type); + error ("return type `%#T' is incomplete", TREE_TYPE (fntype)); - /* Make it return void instead. */ + /* Make it return void instead, but don't change the + type of the DECL_RESULT, in case we have a named return value. */ if (TREE_CODE (fntype) == METHOD_TYPE) - fntype = build_method_type_directly (TREE_TYPE (TREE_VALUE (args)), - void_type_node, - TREE_CHAIN (args)); + { + tree ctype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype))); + TREE_TYPE (decl) + = build_method_type_directly (ctype, + void_type_node, + FUNCTION_ARG_CHAIN (decl)); + } else - fntype = build_function_type (void_type_node, args); + TREE_TYPE (decl) + = build_function_type (void_type_node, + TYPE_ARG_TYPES (TREE_TYPE (decl))); TREE_TYPE (decl) = build_exception_variant (fntype, - TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl))); + TYPE_RAISES_EXCEPTIONS (fntype)); } else abstract_virtuals_error (decl, TREE_TYPE (fntype)); @@ -10436,50 +10169,96 @@ check_function_type (tree decl, tree current_function_parms) This function creates a binding context for the function body as well as setting up the FUNCTION_DECL in current_function_decl. + Returns 1 on success. If the DECLARATOR is not suitable for a function + (it defines a datum instead), we return 0, which tells + yyparse to report a parse error. + For C++, we must first check whether that datum makes any sense. For example, "class A local_a(1,2);" means that variable local_a is an aggregate of type A, which should have a constructor applied to it with the argument list [1, 2]. */ -void -start_preparsed_function (tree decl1, tree attrs, int flags) +int +start_function (tree declspecs, tree declarator, tree attrs, int flags) { + tree decl1; tree ctype = NULL_TREE; tree fntype; tree restype; int doing_friend = 0; struct cp_binding_level *bl; tree current_function_parms; - struct c_fileinfo *finfo - = get_fileinfo (LOCATION_FILE (DECL_SOURCE_LOCATION (decl1))); - bool honor_interface; /* Sanity check. */ - gcc_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE); - gcc_assert (TREE_CHAIN (void_list_node) == NULL_TREE); + my_friendly_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE, 160); + my_friendly_assert (TREE_CHAIN (void_list_node) == NULL_TREE, 161); - fntype = TREE_TYPE (decl1); - if (TREE_CODE (fntype) == METHOD_TYPE) - ctype = TYPE_METHOD_BASETYPE (fntype); + /* This should only be done once on the top most decl. */ + if (have_extern_spec) + { + declspecs = tree_cons (NULL_TREE, get_identifier ("extern"), declspecs); + have_extern_spec = false; + } - /* ISO C++ 11.4/5. A friend function defined in a class is in - the (lexical) scope of the class in which it is defined. */ - if (!ctype && DECL_FRIEND_P (decl1)) + if (flags & SF_PRE_PARSED) { - ctype = DECL_FRIEND_CONTEXT (decl1); + decl1 = declarator; - /* CTYPE could be null here if we're dealing with a template; - for example, `inline friend float foo()' inside a template - will have no CTYPE set. */ - if (ctype && TREE_CODE (ctype) != RECORD_TYPE) - ctype = NULL_TREE; - else - doing_friend = 1; + fntype = TREE_TYPE (decl1); + if (TREE_CODE (fntype) == METHOD_TYPE) + ctype = TYPE_METHOD_BASETYPE (fntype); + + /* ISO C++ 11.4/5. A friend function defined in a class is in + the (lexical) scope of the class in which it is defined. */ + if (!ctype && DECL_FRIEND_P (decl1)) + { + ctype = DECL_FRIEND_CONTEXT (decl1); + + /* CTYPE could be null here if we're dealing with a template; + for example, `inline friend float foo()' inside a template + will have no CTYPE set. */ + if (ctype && TREE_CODE (ctype) != RECORD_TYPE) + ctype = NULL_TREE; + else + doing_friend = 1; + } + } + else + { + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, &attrs); + /* If the declarator is not suitable for a function definition, + cause a syntax error. */ + if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL) + return 0; + + cplus_decl_attributes (&decl1, attrs, 0); + + /* If #pragma weak was used, mark the decl weak now. */ + if (global_scope_p (current_binding_level)) + maybe_apply_pragma_weak (decl1); + + fntype = TREE_TYPE (decl1); + + restype = TREE_TYPE (fntype); + + if (TREE_CODE (fntype) == METHOD_TYPE) + ctype = TYPE_METHOD_BASETYPE (fntype); + else if (DECL_MAIN_P (decl1)) + { + /* If this doesn't return integer_type, or a typedef to + integer_type, complain. */ + if (!same_type_p (TREE_TYPE (TREE_TYPE (decl1)), integer_type_node)) + { + if (pedantic || warn_return_type) + pedwarn ("return type for `main' changed to `int'"); + TREE_TYPE (decl1) = fntype = default_function_type; + } + } } if (DECL_DECLARED_INLINE_P (decl1) && lookup_attribute ("noinline", attrs)) - warning (0, "inline function %q+D given attribute noinline", decl1); + warning ("%Jinline function '%D' given attribute noinline", decl1, decl1); if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl1)) /* This is a constructor, we must ensure that any default args @@ -10496,6 +10275,12 @@ start_preparsed_function (tree decl1, tree attrs, int flags) ctype = NULL_TREE; } + /* Warn if function was previously implicitly declared + (but not if we warned then). */ + if (! warn_implicit + && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)) != NULL_TREE) + cp_warning_at ("`%D' implicitly declared before its definition", IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1))); + /* Set up current_class_type, and enter the scope of the class, if appropriate. */ if (ctype) @@ -10516,7 +10301,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) if (warn_ecpp && DECL_OVERLOADED_OPERATOR_P (decl1) == NOP_EXPR && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE) - warning (OPT_Weffc__, "%<operator=%> should return a reference to %<*this%>"); + warning ("`operator=' should return a reference to `*this'"); /* Make the init_value nonzero so pushdecl knows this is not tentative. error_mark_node is replaced below (in poplevel) with the BLOCK. */ @@ -10533,7 +10318,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags) by push_nested_class.) */ if (processing_template_decl) { - /* FIXME: Handle error_mark_node more gracefully. */ tree newdecl1 = push_template_decl (decl1); if (newdecl1 != error_mark_node) decl1 = newdecl1; @@ -10549,7 +10333,10 @@ start_preparsed_function (tree decl1, tree attrs, int flags) /* Make sure the parameter and return types are reasonable. When you declare a function, these types can be incomplete, but they must be complete when you define the function. */ - check_function_type (decl1, current_function_parms); + if (! processing_template_decl) + check_function_type (decl1, current_function_parms); + /* Make sure no default arg is missing. */ + check_default_args (decl1); /* Build the return declaration for the function. */ restype = TREE_TYPE (fntype); @@ -10558,14 +10345,10 @@ start_preparsed_function (tree decl1, tree attrs, int flags) restype = type_promotes_to (restype); if (DECL_RESULT (decl1) == NULL_TREE) { - tree resdecl; - - resdecl = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype)); - DECL_ARTIFICIAL (resdecl) = 1; - DECL_IGNORED_P (resdecl) = 1; - DECL_RESULT (decl1) = resdecl; - - cp_apply_type_quals_to_decl (cp_type_quals (restype), resdecl); + DECL_RESULT (decl1) + = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype)); + c_apply_type_quals_to_decl (cp_type_quals (restype), + DECL_RESULT (decl1)); } /* Initialize RTL machinery. We cannot do this until @@ -10581,10 +10364,11 @@ start_preparsed_function (tree decl1, tree attrs, int flags) call expand_expr to calculate the size of a variable-sized array. We haven't necessarily assigned RTL to all variables yet, so it's not safe to try to expand expressions involving them. */ + immediate_size_expand = 0; cfun->x_dont_save_pending_sizes_p = 1; /* Start the statement-tree, start the tree now. */ - DECL_SAVED_TREE (decl1) = push_stmt_list (); + begin_stmt_tree (&DECL_SAVED_TREE (decl1)); /* Let the user know we're compiling this function. */ announce_function (decl1); @@ -10596,7 +10380,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) { /* A specialization is not used to guide overload resolution. */ if (!DECL_FUNCTION_MEMBER_P (decl1) - && !(DECL_USE_TEMPLATE (decl1) && + && !(DECL_USE_TEMPLATE (decl1) && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl1)))) { tree olddecl = pushdecl (decl1); @@ -10618,17 +10402,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags) DECL_CONTEXT (decl1) = DECL_CONTEXT (DECL_TI_TEMPLATE (decl1)); } fntype = TREE_TYPE (decl1); - - /* If #pragma weak applies, mark the decl appropriately now. - The pragma only applies to global functions. Because - determining whether or not the #pragma applies involves - computing the mangled name for the declaration, we cannot - apply the pragma until after we have merged this declaration - with any previous declarations; if the original declaration - has a linkage specification, that specification applies to - the definition as well, and may affect the mangled name. */ - if (!DECL_CONTEXT (decl1)) - maybe_apply_pragma_weak (decl1); } /* Reset these in case the call to pushdecl changed them. */ @@ -10648,8 +10421,10 @@ start_preparsed_function (tree decl1, tree attrs, int flags) between `current_class_type' and `current_class_ptr'. */ tree t = DECL_ARGUMENTS (decl1); - gcc_assert (t != NULL_TREE && TREE_CODE (t) == PARM_DECL); - gcc_assert (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE); + my_friendly_assert (t != NULL_TREE && TREE_CODE (t) == PARM_DECL, + 162); + my_friendly_assert (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE, + 19990811); cp_function_chain->x_current_class_ref = build_indirect_ref (t, NULL); @@ -10665,20 +10440,12 @@ start_preparsed_function (tree decl1, tree attrs, int flags) } if (DECL_HAS_VTT_PARM_P (decl1)) { - gcc_assert (DECL_NAME (t) == vtt_parm_identifier); + if (DECL_NAME (t) != vtt_parm_identifier) + abort (); current_vtt_parm = t; } } - honor_interface = (!DECL_TEMPLATE_INSTANTIATION (decl1) - /* Implicitly-defined methods (like the - destructor for a class in which no destructor - is explicitly declared) must not be defined - until their definition is needed. So, we - ignore interface specifications for - compiler-generated functions. */ - && !DECL_ARTIFICIAL (decl1)); - if (DECL_INTERFACE_KNOWN (decl1)) { tree ctx = decl_function_context (decl1); @@ -10695,15 +10462,16 @@ start_preparsed_function (tree decl1, tree attrs, int flags) /* If this function belongs to an interface, it is public. If it belongs to someone else's interface, it is also external. This only affects inlines and template instantiations. */ - else if (!finfo->interface_unknown && honor_interface) + else if (interface_unknown == 0 + && ! DECL_TEMPLATE_INSTANTIATION (decl1)) { - if (DECL_DECLARED_INLINE_P (decl1) + if (DECL_DECLARED_INLINE_P (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1) || processing_template_decl) { DECL_EXTERNAL (decl1) - = (finfo->interface_only - || (DECL_DECLARED_INLINE_P (decl1) + = (interface_only + || (DECL_DECLARED_INLINE_P (decl1) && ! flag_implement_inlines && !DECL_VINDEX (decl1))); @@ -10712,22 +10480,17 @@ start_preparsed_function (tree decl1, tree attrs, int flags) } else DECL_EXTERNAL (decl1) = 0; + DECL_NOT_REALLY_EXTERN (decl1) = 0; DECL_INTERFACE_KNOWN (decl1) = 1; - /* If this function is in an interface implemented in this file, - make sure that the backend knows to emit this function - here. */ - if (!DECL_EXTERNAL (decl1)) - mark_needed (decl1); } - else if (finfo->interface_unknown && finfo->interface_only - && honor_interface) + else if (interface_unknown && interface_only + && ! DECL_TEMPLATE_INSTANTIATION (decl1)) { /* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma - interface, we will have both finfo->interface_unknown and - finfo->interface_only set. In that case, we don't want to - use the normal heuristics because someone will supply a - #pragma implementation elsewhere, and deducing it here would - produce a conflict. */ + interface, we will have interface_only set but not + interface_known. In that case, we don't want to use the normal + heuristics because someone will supply a #pragma implementation + elsewhere, and deducing it here would produce a conflict. */ comdat_linkage (decl1); DECL_EXTERNAL (decl1) = 0; DECL_INTERFACE_KNOWN (decl1) = 1; @@ -10739,7 +10502,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) So clear DECL_EXTERNAL. */ DECL_EXTERNAL (decl1) = 0; - if ((DECL_DECLARED_INLINE_P (decl1) + if ((DECL_DECLARED_INLINE_P (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1)) && ! DECL_INTERFACE_KNOWN (decl1) /* Don't try to defer nested functions for now. */ @@ -10749,86 +10512,23 @@ start_preparsed_function (tree decl1, tree attrs, int flags) DECL_INTERFACE_KNOWN (decl1) = 1; } - /* Determine the ELF visibility attribute for the function. We must not - do this before calling "pushdecl", as we must allow "duplicate_decls" - to merge any attributes appropriately. We also need to wait until - linkage is set. */ - if (!DECL_CLONED_FUNCTION_P (decl1)) - determine_visibility (decl1); - begin_scope (sk_function_parms, decl1); ++function_depth; - if (DECL_DESTRUCTOR_P (decl1) - || (DECL_CONSTRUCTOR_P (decl1) - && targetm.cxx.cdtor_returns_this ())) + if (DECL_DESTRUCTOR_P (decl1)) { - cdtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); - DECL_CONTEXT (cdtor_label) = current_function_decl; + dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + DECL_CONTEXT (dtor_label) = current_function_decl; } start_fname_decls (); - + store_parm_decls (current_function_parms); -} - - -/* Like start_preparsed_function, except that instead of a - FUNCTION_DECL, this function takes DECLSPECS and DECLARATOR. - - Returns 1 on success. If the DECLARATOR is not suitable for a function - (it defines a datum instead), we return 0, which tells - yyparse to report a parse error. */ - -int -start_function (cp_decl_specifier_seq *declspecs, - const cp_declarator *declarator, - tree attrs) -{ - tree decl1; - - decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, &attrs); - /* If the declarator is not suitable for a function definition, - cause a syntax error. */ - if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL) - return 0; - - if (DECL_MAIN_P (decl1)) - /* main must return int. grokfndecl should have corrected it - (and issued a diagnostic) if the user got it wrong. */ - gcc_assert (same_type_p (TREE_TYPE (TREE_TYPE (decl1)), - integer_type_node)); - - start_preparsed_function (decl1, attrs, /*flags=*/SF_DEFAULT); return 1; } -/* Returns true iff an EH_SPEC_BLOCK should be created in the body of - FN. */ - -static bool -use_eh_spec_block (tree fn) -{ - return (flag_exceptions && flag_enforce_eh_specs - && !processing_template_decl - && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)) - /* We insert the EH_SPEC_BLOCK only in the original - function; then, it is copied automatically to the - clones. */ - && !DECL_CLONED_FUNCTION_P (fn) - /* Implicitly-generated constructors and destructors have - exception specifications. However, those specifications - are the union of the possible exceptions specified by the - constructors/destructors for bases and members, so no - unallowed exception will ever reach this function. By - not creating the EH_SPEC_BLOCK we save a little memory, - and we avoid spurious warnings about unreachable - code. */ - && !DECL_ARTIFICIAL (fn)); -} - /* Store the parameter declarations into the current function declaration. This is called after parsing the parameter declarations, before digesting the body of the function. @@ -10874,7 +10574,7 @@ store_parm_decls (tree current_function_parms) || TREE_CODE (parm) != VOID_TYPE) pushdecl (parm); else - error ("parameter %qD declared void", parm); + error ("parameter `%D' declared void", parm); } else { @@ -10899,7 +10599,10 @@ store_parm_decls (tree current_function_parms) DECL_ARGUMENTS is not modified. */ current_binding_level->names = chainon (nonparms, DECL_ARGUMENTS (fndecl)); - if (use_eh_spec_block (current_function_decl)) + /* Do the starting of the exception specifications, if we have any. */ + if (flag_exceptions && !processing_template_decl + && flag_enforce_eh_specs + && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) current_eh_spec_block = begin_eh_spec_block (); } @@ -10915,40 +10618,47 @@ save_function_data (tree decl) /* Save the language-specific per-function data so that we can get it back when we really expand this function. */ - gcc_assert (!DECL_PENDING_INLINE_P (decl)); + my_friendly_assert (!DECL_PENDING_INLINE_P (decl), + 19990908); /* Make a copy. */ - f = GGC_NEW (struct language_function); + f = ggc_alloc (sizeof (struct language_function)); memcpy (f, cp_function_chain, sizeof (struct language_function)); DECL_SAVED_FUNCTION_DATA (decl) = f; /* Clear out the bits we don't need. */ - f->base.x_stmt_tree.x_cur_stmt_list = NULL_TREE; + f->base.x_stmt_tree.x_last_stmt = NULL_TREE; + f->base.x_stmt_tree.x_last_expr_type = NULL_TREE; + f->x_named_label_uses = NULL; f->bindings = NULL; f->x_local_names = NULL; -} + /* If we've already decided that we cannot inline this function, we + must remember that fact when we actually go to expand the + function. */ + if (current_function_cannot_inline) + { + f->cannot_inline = current_function_cannot_inline; + DECL_INLINE (decl) = 0; + } +} -/* Set the return value of the constructor (if present). */ +/* Add a note to mark the beginning of the main body of the constructor. + This is used to set up the data structures for the cleanup regions for + fully-constructed bases and members. */ static void -finish_constructor_body (void) +begin_constructor_body (void) { - tree val; - tree exprstmt; +} - if (targetm.cxx.cdtor_returns_this ()) - { - /* Any return from a constructor will end up here. */ - add_stmt (build_stmt (LABEL_EXPR, cdtor_label)); +/* Add a note to mark the end of the main body of the constructor. This is + used to end the cleanup regions for fully-constructed bases and + members. */ - val = DECL_ARGUMENTS (current_function_decl); - val = build2 (MODIFY_EXPR, TREE_TYPE (val), - DECL_RESULT (current_function_decl), val); - /* Return the address of the object. */ - exprstmt = build_stmt (RETURN_EXPR, val); - add_stmt (exprstmt); - } +static void +finish_constructor_body (void) +{ } /* Do all the processing for the beginning of a destructor; set up the @@ -10957,25 +10667,45 @@ finish_constructor_body (void) static void begin_destructor_body (void) { + tree if_stmt; tree compound_stmt; - /* If the CURRENT_CLASS_TYPE is incomplete, we will have already - issued an error message. We still want to try to process the - body of the function, but initialize_vtbl_ptrs will crash if - TYPE_BINFO is NULL. */ - if (COMPLETE_TYPE_P (current_class_type)) - { - compound_stmt = begin_compound_stmt (0); - /* Make all virtual function table pointers in non-virtual base - classes point to CURRENT_CLASS_TYPE's virtual function - tables. */ - initialize_vtbl_ptrs (current_class_ptr); - finish_compound_stmt (compound_stmt); + /* If the dtor is empty, and we know there is not any possible + way we could use any vtable entries, before they are possibly + set by a base class dtor, we don't have to setup the vtables, + as we know that any base class dtor will set up any vtables + it needs. We avoid MI, because one base class dtor can do a + virtual dispatch to an overridden function that would need to + have a non-related vtable set up, we cannot avoid setting up + vtables in that case. We could change this to see if there + is just one vtable. + + ??? In the destructor for a class, the vtables are set + appropriately for that class. There will be no non-related + vtables. jason 2001-12-11. */ + if_stmt = begin_if_stmt (); + + /* If it is not safe to avoid setting up the vtables, then + someone will change the condition to be boolean_true_node. + (Actually, for now, we do not have code to set the condition + appropriately, so we just assume that we always need to + initialize the vtables.) */ + finish_if_stmt_cond (boolean_true_node, if_stmt); + + compound_stmt = begin_compound_stmt (/*has_no_scope=*/false); + + /* Make all virtual function table pointers in non-virtual base + classes point to CURRENT_CLASS_TYPE's virtual function + tables. */ + initialize_vtbl_ptrs (current_class_ptr); - /* And insert cleanups for our bases and members so that they - will be properly destroyed if we throw. */ - push_base_cleanups (); - } + finish_compound_stmt (compound_stmt); + finish_then_clause (if_stmt); + finish_if_stmt (); + + /* And insert cleanups for our bases and members so that they + will be properly destroyed if we throw. */ + push_base_cleanups (); } /* At the end of every destructor we generate code to delete the object if @@ -10988,7 +10718,7 @@ finish_destructor_body (void) /* Any return from a destructor will end up here; that way all base and member cleanups will be run when the function returns. */ - add_stmt (build_stmt (LABEL_EXPR, cdtor_label)); + add_stmt (build_stmt (LABEL_STMT, dtor_label)); /* In a virtual destructor, we must call delete. */ if (DECL_VIRTUAL_P (current_function_decl)) @@ -11002,48 +10732,32 @@ finish_destructor_body (void) an implicit definition), non-placement operator delete shall be looked up in the scope of the destructor's class and if found shall be accessible and unambiguous. */ - exprstmt = build_op_delete_call(DELETE_EXPR, current_class_ptr, - virtual_size, - /*global_p=*/false, - /*placement=*/NULL_TREE, - /*alloc_fn=*/NULL_TREE); + exprstmt = build_op_delete_call + (DELETE_EXPR, current_class_ptr, virtual_size, + LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE); if_stmt = begin_if_stmt (); - finish_if_stmt_cond (build2 (BIT_AND_EXPR, integer_type_node, - current_in_charge_parm, - integer_one_node), + finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node, + current_in_charge_parm, + integer_one_node), if_stmt); finish_expr_stmt (exprstmt); finish_then_clause (if_stmt); - finish_if_stmt (if_stmt); - } - - if (targetm.cxx.cdtor_returns_this ()) - { - tree val; - - val = DECL_ARGUMENTS (current_function_decl); - val = build2 (MODIFY_EXPR, TREE_TYPE (val), - DECL_RESULT (current_function_decl), val); - /* Return the address of the object. */ - exprstmt = build_stmt (RETURN_EXPR, val); - add_stmt (exprstmt); + finish_if_stmt (); } } /* Do the necessary processing for the beginning of a function body, which in this case includes member-initializers, but not the catch clauses of a function-try-block. Currently, this means opening a binding level - for the member-initializers (in a ctor) and member cleanups (in a dtor). */ + for the member-initializers (in a ctor) and member cleanups (in a dtor). + In other functions, this isn't necessary, but it doesn't hurt. */ tree begin_function_body (void) { tree stmt; - if (! FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)) - return NULL_TREE; - if (processing_template_decl) /* Do nothing now. */; else @@ -11052,10 +10766,13 @@ begin_function_body (void) operation of dwarfout.c. */ keep_next_level (true); - stmt = begin_compound_stmt (BCS_FN_BODY); + stmt = begin_compound_stmt (/*has_no_scope=*/false); + COMPOUND_STMT_BODY_BLOCK (stmt) = 1; if (processing_template_decl) /* Do nothing now. */; + else if (DECL_CONSTRUCTOR_P (current_function_decl)) + begin_constructor_body (); else if (DECL_DESTRUCTOR_P (current_function_decl)) begin_destructor_body (); @@ -11074,9 +10791,6 @@ begin_function_body (void) void finish_function_body (tree compstmt) { - if (compstmt == NULL_TREE) - return; - /* Close the block. */ finish_compound_stmt (compstmt); @@ -11086,21 +10800,7 @@ finish_function_body (tree compstmt) finish_constructor_body (); else if (DECL_DESTRUCTOR_P (current_function_decl)) finish_destructor_body (); -} - -/* Given a function, returns the BLOCK corresponding to the outermost level - of curly braces, skipping the artificial block created for constructor - initializers. */ - -static tree -outer_curly_brace_block (tree fndecl) -{ - tree block = BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl)); - if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)) - /* Skip the artificial function body block. */ - block = BLOCK_SUBBLOCKS (block); - return block; -} +} /* Finish up a function declaration and compile that function all the way to assembler language output. The free the storage @@ -11141,66 +10841,58 @@ finish_function (int flags) This caused &foo to be of type ptr-to-const-function which then got a warning when stored in a ptr-to-function variable. */ - gcc_assert (building_stmt_tree ()); - + my_friendly_assert (building_stmt_tree (), 20000911); + /* For a cloned function, we've already got all the code we need; there's no need to add any extra bits. */ if (!DECL_CLONED_FUNCTION_P (fndecl)) { if (DECL_MAIN_P (current_function_decl)) { - tree stmt; - - /* Make it so that `main' always returns 0 by default (or - 1 for VMS). */ + /* Make it so that `main' always returns 0 by default. */ #if VMS_TARGET - stmt = finish_return_stmt (integer_one_node); -#else - stmt = finish_return_stmt (integer_zero_node); -#endif - /* Hack. We don't want the middle-end to warn that this - return is unreachable, so put the statement on the - special line 0. */ -#ifdef USE_MAPPED_LOCATION - SET_EXPR_LOCATION (stmt, UNKNOWN_LOCATION); + finish_return_stmt (integer_one_node); #else - annotate_with_file_line (stmt, input_filename, 0); + finish_return_stmt (integer_zero_node); #endif } - if (use_eh_spec_block (current_function_decl)) + /* Finish dealing with exception specifiers. */ + if (flag_exceptions && !processing_template_decl + && flag_enforce_eh_specs + && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) finish_eh_spec_block (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)), current_eh_spec_block); } - /* If we're saving up tree structure, tie off the function now. */ - DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl)); - finish_fname_decls (); + /* If we're saving up tree structure, tie off the function now. */ + finish_stmt_tree (&DECL_SAVED_TREE (fndecl)); + /* If this function can't throw any exceptions, remember that. */ if (!processing_template_decl && !cp_function_chain->can_throw - && !flag_non_call_exceptions - && !DECL_REPLACEABLE_P (fndecl)) + && !flag_non_call_exceptions) TREE_NOTHROW (fndecl) = 1; /* This must come after expand_function_end because cleanups might have declarations (from inline functions) that need to go into this function's blocks. */ - + /* If the current binding level isn't the outermost binding level for this function, either there is a bug, or we have experienced syntax errors and the statement tree is malformed. */ if (current_binding_level->kind != sk_function_parms) { /* Make sure we have already experienced errors. */ - gcc_assert (errorcount); + if (errorcount == 0) + abort (); /* Throw away the broken statement tree and extra binding - levels. */ - DECL_SAVED_TREE (fndecl) = alloc_stmt_list (); + levels. */ + DECL_SAVED_TREE (fndecl) = build_stmt (COMPOUND_STMT, NULL_TREE); while (current_binding_level->kind != sk_function_parms) { @@ -11214,10 +10906,12 @@ finish_function (int flags) /* Statements should always be full-expressions at the outermost set of curly braces for a function. */ - gcc_assert (stmts_are_full_exprs_p ()); + my_friendly_assert (stmts_are_full_exprs_p (), 19990831); - /* Set up the named return value optimization, if we can. Candidate - variables are selected in check_return_value. */ + /* Set up the named return value optimization, if we can. Here, we + eliminate the copy from the nrv into the RESULT_DECL and any cleanup + for the nrv. genrtl_start_function and declare_return_variable + handle making the nrv and RESULT_DECL share space. */ if (current_function_return_value) { tree r = current_function_return_value; @@ -11231,11 +10925,19 @@ finish_function (int flags) the function so we know that their lifetime always ends with a return; see g++.dg/opt/nrv6.C. We could be more flexible if we were to do this optimization in tree-ssa. */ - && (outer = outer_curly_brace_block (fndecl)) - && chain_member (r, BLOCK_VARS (outer))) - finalize_nrv (&DECL_SAVED_TREE (fndecl), r, DECL_RESULT (fndecl)); - - current_function_return_value = NULL_TREE; + /* Skip the artificial function body block. */ + && (outer = BLOCK_SUBBLOCKS (BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl))), + chain_member (r, BLOCK_VARS (outer)))) + { + + DECL_ALIGN (r) = DECL_ALIGN (DECL_RESULT (fndecl)); + walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl), + nullify_returns_r, r); + } + else + /* Clear it so genrtl_start_function and declare_return_variable + know we're not optimizing. */ + current_function_return_value = NULL_TREE; } /* Remember that we were in class scope. */ @@ -11253,6 +10955,18 @@ finish_function (int flags) if (!processing_template_decl) save_function_data (fndecl); + /* If this function calls `setjmp' it cannot be inlined. When + `longjmp' is called it is not guaranteed to restore the value of + local variables that have been modified since the call to + `setjmp'. So, if were to inline this function into some caller + `c', then when we `longjmp', we might not restore all variables + in `c'. (It might seem, at first blush, that there's no way for + this function to modify local variables in `c', but their + addresses may have been stored somewhere accessible to this + function.) */ + if (!processing_template_decl && calls_setjmp_p (fndecl)) + DECL_UNINLINABLE (fndecl) = 1; + /* Complain if there's just no return statement. */ if (warn_return_type && TREE_CODE (TREE_TYPE (fntype)) != VOID_TYPE @@ -11263,39 +10977,11 @@ finish_function (int flags) && !DECL_NAME (DECL_RESULT (fndecl)) /* Normally, with -Wreturn-type, flow will complain. Unless we're an inline function, as we might never be compiled separately. */ - && (DECL_INLINE (fndecl) || processing_template_decl) - /* Structor return values (if any) are set by the compiler. */ - && !DECL_CONSTRUCTOR_P (fndecl) - && !DECL_DESTRUCTOR_P (fndecl)) - warning (OPT_Wreturn_type, "no return statement in function returning non-void"); - - /* Store the end of the function, so that we get good line number - info for the epilogue. */ - cfun->function_end_locus = input_location; - - /* Genericize before inlining. */ - if (!processing_template_decl) - { - struct language_function *f = DECL_SAVED_FUNCTION_DATA (fndecl); - cp_genericize (fndecl); - /* Clear out the bits we don't need. */ - f->x_current_class_ptr = NULL; - f->x_current_class_ref = NULL; - f->x_eh_spec_block = NULL; - f->x_in_charge_parm = NULL; - f->x_vtt_parm = NULL; - f->x_return_value = NULL; - f->bindings = NULL; - f->extern_decl_map = NULL; - - /* Handle attribute((warn_unused_result)). Relies on gimple input. */ - c_warn_unused_result (&DECL_SAVED_TREE (fndecl)); - } - /* Clear out the bits we don't need. */ - local_names = NULL; + && (DECL_INLINE (fndecl) || processing_template_decl)) + warning ("no return statement in function returning non-void"); /* We're leaving the context of this function, so zap cfun. It's still in - DECL_STRUCT_FUNCTION, and we'll restore it in tree_rest_of_compilation. */ + DECL_SAVED_INSNS, and we'll restore it in tree_rest_of_compilation. */ cfun = NULL; current_function_decl = NULL; @@ -11344,8 +11030,7 @@ finish_function (int flags) CHANGES TO CODE IN `grokfield'. */ tree -start_method (cp_decl_specifier_seq *declspecs, - const cp_declarator *declarator, tree attrlist) +start_method (tree declspecs, tree declarator, tree attrlist) { tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, &attrlist); @@ -11368,11 +11053,14 @@ start_method (cp_decl_specifier_seq *declspecs, if (DECL_IN_AGGR_P (fndecl)) { - if (DECL_CONTEXT (fndecl) - && TREE_CODE (DECL_CONTEXT (fndecl)) != NAMESPACE_DECL) - error ("%qD is already defined in class %qT", fndecl, - DECL_CONTEXT (fndecl)); - return error_mark_node; + if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (fndecl)) != current_class_type) + { + if (DECL_CONTEXT (fndecl) + && TREE_CODE( DECL_CONTEXT (fndecl)) != NAMESPACE_DECL) + error ("`%D' is already defined in class `%T'", fndecl, + DECL_CONTEXT (fndecl)); + } + return void_type_node; } check_template_shadow (fndecl); @@ -11396,9 +11084,10 @@ start_method (cp_decl_specifier_seq *declspecs, fndecl = copy_node (fndecl); TREE_CHAIN (fndecl) = NULL_TREE; } + grok_special_member_properties (fndecl); } - finish_decl (fndecl, NULL_TREE, NULL_TREE); + cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0); /* Make a place for the parms. */ begin_scope (sk_function_parms, fndecl); @@ -11446,7 +11135,7 @@ finish_method (tree decl) { if (DECL_NAME (link) != NULL_TREE) pop_binding (DECL_NAME (link), link); - gcc_assert (TREE_CODE (link) != FUNCTION_DECL); + my_friendly_assert (TREE_CODE (link) != FUNCTION_DECL, 163); DECL_CONTEXT (link) = NULL_TREE; } @@ -11459,8 +11148,8 @@ finish_method (tree decl) for String.cc in libg++. */ if (DECL_FRIEND_P (fndecl)) { - VEC_safe_push (tree, gc, CLASSTYPE_INLINE_FRIENDS (current_class_type), - fndecl); + CLASSTYPE_INLINE_FRIENDS (current_class_type) + = tree_cons (NULL_TREE, fndecl, CLASSTYPE_INLINE_FRIENDS (current_class_type)); decl = void_type_node; } @@ -11474,18 +11163,18 @@ finish_method (tree decl) void maybe_register_incomplete_var (tree var) { - gcc_assert (TREE_CODE (var) == VAR_DECL); + my_friendly_assert (TREE_CODE (var) == VAR_DECL, 20020406); /* Keep track of variables with incomplete types. */ - if (!processing_template_decl && TREE_TYPE (var) != error_mark_node + if (!processing_template_decl && TREE_TYPE (var) != error_mark_node && DECL_EXTERNAL (var)) { tree inner_type = TREE_TYPE (var); - + while (TREE_CODE (inner_type) == ARRAY_TYPE) inner_type = TREE_TYPE (inner_type); inner_type = TYPE_MAIN_VARIANT (inner_type); - + if ((!COMPLETE_TYPE_P (inner_type) && CLASS_TYPE_P (inner_type)) /* RTTI TD entries are created while defining the type_info. */ || (TYPE_LANG_SPECIFIC (inner_type) @@ -11503,26 +11192,21 @@ complete_vars (tree type) { tree *list = &incomplete_vars; - gcc_assert (CLASS_TYPE_P (type)); - while (*list) + my_friendly_assert (CLASS_TYPE_P (type), 20020406); + while (*list) { if (same_type_p (type, TREE_PURPOSE (*list))) { tree var = TREE_VALUE (*list); - tree type = TREE_TYPE (var); /* Complete the type of the variable. The VAR_DECL itself will be laid out in expand_expr. */ - complete_type (type); - cp_apply_type_quals_to_decl (cp_type_quals (type), var); + complete_type (TREE_TYPE (var)); /* Remove this entry from the list. */ *list = TREE_CHAIN (*list); } else list = &TREE_CHAIN (*list); } - - /* Check for pending declarations which may have abstract type. */ - complete_type_check_abstract (type); } /* If DECL is of a type which needs a cleanup, build that cleanup @@ -11537,8 +11221,6 @@ cxx_maybe_build_cleanup (tree decl) { int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR; tree rval; - bool has_vbases = (TREE_CODE (type) == RECORD_TYPE - && CLASSTYPE_VBASECLASSES (type)); if (TREE_CODE (type) == ARRAY_TYPE) rval = decl; @@ -11549,12 +11231,17 @@ cxx_maybe_build_cleanup (tree decl) } /* Optimize for space over speed here. */ - if (!has_vbases || flag_expensive_optimizations) + if (! TYPE_USES_VIRTUAL_BASECLASSES (type) + || flag_expensive_optimizations) flags |= LOOKUP_NONVIRTUAL; rval = build_delete (TREE_TYPE (rval), rval, sfk_complete_destructor, flags, 0); + if (TYPE_USES_VIRTUAL_BASECLASSES (type) + && ! TYPE_HAS_DESTRUCTOR (type)) + rval = build_compound_expr (rval, build_vbase_delete (type, decl)); + return rval; } return NULL_TREE; @@ -11565,6 +11252,10 @@ cxx_maybe_build_cleanup (tree decl) void finish_stmt (void) { + /* Always assume this statement was not an expression statement. If + it actually was an expression statement, its our callers + responsibility to fix this up. */ + last_expr_type = NULL_TREE; } /* DECL was originally constructed as a non-static member function, @@ -11579,7 +11270,8 @@ revert_static_member_fn (tree decl) if (cp_type_quals (TREE_TYPE (TREE_VALUE (args))) != TYPE_UNQUALIFIED) - error ("static member function %q#D declared with type qualifiers", decl); + error ("static member function `%#D' declared with type qualifiers", + decl); args = TREE_CHAIN (args); tmp = build_function_type (TREE_TYPE (function), args); @@ -11598,7 +11290,8 @@ revert_static_member_fn (tree decl) void cxx_push_function_context (struct function * f) { - struct language_function *p = GGC_CNEW (struct language_function); + struct language_function *p + = ggc_alloc_cleared (sizeof (struct language_function)); f->language = p; /* Whenever we start a new function, we destroy temporaries in the @@ -11615,9 +11308,14 @@ cxx_push_function_context (struct function * f) now, restore saved state. */ *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn); + /* If we decided that we didn't want to inline this function, + make sure the back-end knows that. */ + if (!current_function_cannot_inline) + current_function_cannot_inline = cp_function_chain->cannot_inline; + /* We don't need the saved data anymore. Unless this is an inline function; we need the named return value info for - declare_return_variable. */ + cp_copy_res_decl_for_inlining. */ if (! DECL_INLINE (fn)) DECL_SAVED_FUNCTION_DATA (fn) = NULL; } @@ -11645,9 +11343,9 @@ cp_tree_node_structure (union lang_tree_node * t) case IDENTIFIER_NODE: return TS_CP_IDENTIFIER; case OVERLOAD: return TS_CP_OVERLOAD; case TEMPLATE_PARM_INDEX: return TS_CP_TPI; - case TINST_LEVEL: return TS_CP_TINST_LEVEL; case PTRMEM_CST: return TS_CP_PTRMEM; - case BASELINK: return TS_CP_BASELINK; + case BASELINK: return TS_CP_BASELINK; + case WRAPPER: return TS_CP_WRAPPER; default: return TS_CP_GENERIC; } } @@ -11657,49 +11355,16 @@ tree build_void_list_node (void) { tree t = build_tree_list (NULL_TREE, void_type_node); + TREE_PARMLIST (t) = 1; return t; } -bool +static int cp_missing_noreturn_ok_p (tree decl) { /* A missing noreturn is ok for the `main' function. */ return DECL_MAIN_P (decl); } -/* Return the COMDAT group into which DECL should be placed. */ - -const char * -cxx_comdat_group (tree decl) -{ - tree name; - - /* Virtual tables, construction virtual tables, and virtual table - tables all go in a single COMDAT group, named after the primary - virtual table. */ - if (TREE_CODE (decl) == VAR_DECL && DECL_VTABLE_OR_VTT_P (decl)) - name = DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (DECL_CONTEXT (decl))); - /* For all other DECLs, the COMDAT group is the mangled name of the - declaration itself. */ - else - { - while (DECL_THUNK_P (decl)) - { - /* If TARGET_USE_LOCAL_THUNK_ALIAS_P, use_thunk puts the thunk - into the same section as the target function. In that case - we must return target's name. */ - tree target = THUNK_TARGET (decl); - if (TARGET_USE_LOCAL_THUNK_ALIAS_P (target) - && DECL_SECTION_NAME (target) != NULL - && DECL_ONE_ONLY (target)) - decl = target; - else - break; - } - name = DECL_ASSEMBLER_NAME (decl); - } - - return IDENTIFIER_POINTER (name); -} - #include "gt-cp-decl.h" +#include "gtype-cp.h" diff --git a/contrib/gcc/cp/except.c b/contrib/gcc/cp/except.c index f97ab06..e61e652 100644 --- a/contrib/gcc/cp/except.c +++ b/contrib/gcc/cp/except.c @@ -1,6 +1,6 @@ /* Handle exceptional things in C++. Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Michael Tiemann <tiemann@cygnus.com> Rewritten by Mike Stump <mrs@cygnus.com>, based upon an initial re-implementation courtesy Tad Hunt. @@ -19,8 +19,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ #include "config.h" @@ -37,8 +37,6 @@ Boston, MA 02110-1301, USA. */ #include "except.h" #include "toplev.h" #include "tree-inline.h" -#include "tree-iterator.h" -#include "target.h" static void push_eh_cleanup (tree); static tree prepare_eh_type (tree); @@ -53,6 +51,7 @@ static tree wrap_cleanups_r (tree *, int *, void *); static int complete_ptr_ref_or_void_ptr_p (tree, tree); static bool is_admissible_throw_operand (tree); static int can_convert_eh (tree, tree); +static void check_handlers_1 (tree, tree); static tree cp_protect_cleanup_actions (void); /* Sets up all the global eh stuff that needs to be initialized at the @@ -80,10 +79,6 @@ init_exception_processing (void) eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS ? "__gxx_personality_sj0" : "__gxx_personality_v0"); - if (targetm.arm_eabi_unwinder) - unwind_resume_libfunc = init_one_libfunc ("__cxa_end_cleanup"); - else - default_init_unwind_resume_libfunc (); lang_eh_runtime_type = build_eh_type_type; lang_protect_cleanup_actions = &cp_protect_cleanup_actions; @@ -100,7 +95,7 @@ cp_protect_cleanup_actions (void) When the destruction of an object during stack unwinding exits using an exception ... void terminate(); is called. */ return build_call (terminate_node, NULL_TREE); -} +} static tree prepare_eh_type (tree type) @@ -149,33 +144,13 @@ build_eh_type_type (tree type) mark_used (exp); - return convert (ptr_type_node, build_address (exp)); + return build1 (ADDR_EXPR, ptr_type_node, exp); } tree build_exc_ptr (void) { - return build0 (EXC_PTR_EXPR, ptr_type_node); -} - -/* Build up a call to __cxa_get_exception_ptr so that we can build a - copy constructor for the thrown object. */ - -static tree -do_get_exception_ptr (void) -{ - tree fn; - - fn = get_identifier ("__cxa_get_exception_ptr"); - if (!get_global_value_if_present (fn, &fn)) - { - /* Declare void* __cxa_get_exception_ptr (void *). */ - tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); - fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); - } - - return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (), - NULL_TREE)); + return build (EXC_PTR_EXPR, ptr_type_node); } /* Build up a call to __cxa_begin_catch, to tell the runtime that the @@ -207,12 +182,9 @@ dtor_nothrow (tree type) if (type == NULL_TREE) return 0; - if (!CLASS_TYPE_P (type)) + if (! TYPE_HAS_DESTRUCTOR (type)) return 1; - if (CLASSTYPE_LAZY_DESTRUCTOR (type)) - lazily_declare_fn (sfk_destructor, type); - return TREE_NOTHROW (CLASSTYPE_DESTRUCTORS (type)); } @@ -264,8 +236,8 @@ decl_is_java_type (tree decl, int err) && TYPE_FOR_JAVA (TREE_TYPE (decl))) { /* Can't throw a reference. */ - error ("type %qT is disallowed in Java %<throw%> or %<catch%>", - decl); + error ("type `%T' is disallowed in Java `throw' or `catch'", + decl); } if (r) @@ -275,15 +247,15 @@ decl_is_java_type (tree decl, int err) if (jthrow_node == NULL_TREE) fatal_error - ("call to Java %<catch%> or %<throw%> with %<jthrowable%> undefined"); + ("call to Java `catch' or `throw' with `jthrowable' undefined"); jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node)); if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl))) { /* Thrown object must be a Throwable. */ - error ("type %qT is not derived from %<java::lang::Throwable%>", - TREE_TYPE (decl)); + error ("type `%T' is not derived from `java::lang::Throwable'", + TREE_TYPE (decl)); } } } @@ -340,7 +312,7 @@ choose_personality_routine (enum languages lang) break; default: - gcc_unreachable (); + abort (); } return; @@ -351,7 +323,7 @@ choose_personality_routine (enum languages lang) /* Initialize the catch parameter DECL. */ -static void +static void initialize_handler_parm (tree decl, tree exp) { tree init; @@ -362,10 +334,11 @@ initialize_handler_parm (tree decl, tree exp) TREE_USED (decl) = 1; /* Figure out the type that the initializer is. Pointers are returned - adjusted by value from __cxa_begin_catch. Others are returned by + adjusted by value from __cxa_begin_catch. Others are returned by reference. */ init_type = TREE_TYPE (decl); - if (!POINTER_TYPE_P (init_type)) + if (! TYPE_PTR_P (init_type) + && TREE_CODE (init_type) != REFERENCE_TYPE) init_type = build_reference_type (init_type); choose_personality_routine (decl_is_java_type (init_type, 0) @@ -392,10 +365,12 @@ initialize_handler_parm (tree decl, tree exp) init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init); } + /* Let `cp_finish_decl' know that this initializer is ok. */ + DECL_INITIAL (decl) = error_mark_node; decl = pushdecl (decl); - start_decl_1 (decl, true); - cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE, + start_decl_1 (decl); + cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING|DIRECT_BIND); } @@ -404,73 +379,61 @@ initialize_handler_parm (tree decl, tree exp) tree expand_start_catch_block (tree decl) { - tree exp; + tree exp = NULL_TREE; tree type; + bool is_java; if (! doing_eh (1)) return NULL_TREE; /* Make sure this declaration is reasonable. */ if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE)) - decl = error_mark_node; + decl = NULL_TREE; if (decl) type = prepare_eh_type (TREE_TYPE (decl)); else type = NULL_TREE; - if (decl && decl_is_java_type (type, 1)) + is_java = false; + if (decl) { - /* Java only passes object via pointer and doesn't require - adjusting. The java object is immediately before the - generic exception header. */ - exp = build_exc_ptr (); - exp = build1 (NOP_EXPR, build_pointer_type (type), exp); - exp = build2 (MINUS_EXPR, TREE_TYPE (exp), exp, - TYPE_SIZE_UNIT (TREE_TYPE (exp))); - exp = build_indirect_ref (exp, NULL); - initialize_handler_parm (decl, exp); - return type; - } - - /* Call __cxa_end_catch at the end of processing the exception. */ - push_eh_cleanup (type); + tree init; - /* If there's no decl at all, then all we need to do is make sure - to tell the runtime that we've begun handling the exception. */ - if (decl == NULL || decl == error_mark_node) + if (decl_is_java_type (type, 1)) + { + /* Java only passes object via pointer and doesn't require + adjusting. The java object is immediately before the + generic exception header. */ + init = build_exc_ptr (); + init = build1 (NOP_EXPR, build_pointer_type (type), init); + init = build (MINUS_EXPR, TREE_TYPE (init), init, + TYPE_SIZE_UNIT (TREE_TYPE (init))); + init = build_indirect_ref (init, NULL); + is_java = true; + } + else + { + /* C++ requires that we call __cxa_begin_catch to get the + pointer to the actual object. */ + init = do_begin_catch (); + } + + exp = create_temporary_var (ptr_type_node); + DECL_REGISTER (exp) = 1; + cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING); + finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init)); + } + else finish_expr_stmt (do_begin_catch ()); - /* If the C++ object needs constructing, we need to do that before - calling __cxa_begin_catch, so that std::uncaught_exception gets - the right value during the copy constructor. */ - else if (flag_use_cxa_get_exception_ptr - && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) - { - exp = do_get_exception_ptr (); - initialize_handler_parm (decl, exp); - finish_expr_stmt (do_begin_catch ()); - } + /* C++ requires that we call __cxa_end_catch at the end of + processing the exception. */ + if (! is_java) + push_eh_cleanup (type); - /* Otherwise the type uses a bitwise copy, and we don't have to worry - about the value of std::uncaught_exception and therefore can do the - copy with the return value of __cxa_end_catch instead. */ - else - { - tree init = do_begin_catch (); - tree init_type = type; - - /* Pointers are passed by values, everything else by reference. */ - if (!TYPE_PTR_P (type)) - init_type = build_pointer_type (type); - if (init_type != TREE_TYPE (init)) - init = build1 (NOP_EXPR, init_type, init); - exp = create_temporary_var (init_type); - DECL_REGISTER (exp) = 1; - cp_finish_decl (exp, init, /*init_const_expr=*/false, - NULL_TREE, LOOKUP_ONLYCONVERTING); - initialize_handler_parm (decl, exp); - } + if (decl) + initialize_handler_parm (decl, exp); return type; } @@ -499,7 +462,6 @@ begin_eh_spec_block (void) { tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE); add_stmt (r); - EH_SPEC_STMTS (r) = push_stmt_list (); return r; } @@ -508,7 +470,7 @@ finish_eh_spec_block (tree raw_raises, tree eh_spec_block) { tree raises; - EH_SPEC_STMTS (eh_spec_block) = pop_stmt_list (EH_SPEC_STMTS (eh_spec_block)); + RECHAIN_STMTS (eh_spec_block, EH_SPEC_STMTS (eh_spec_block)); /* Strip cv quals, etc, from the specification types. */ for (raises = NULL_TREE; @@ -539,7 +501,7 @@ do_allocate_exception (tree type) tree tmp = tree_cons (NULL_TREE, size_type_node, void_list_node); fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); } - + return build_function_call (fn, tree_cons (NULL_TREE, size_in_bytes (type), NULL_TREE)); } @@ -568,7 +530,7 @@ do_free_exception (tree ptr) static tree wrap_cleanups_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) + void *data ATTRIBUTE_UNUSED) { tree exp = *tp; tree cleanup; @@ -605,18 +567,17 @@ build_throw (tree exp) if (processing_template_decl) { - if (cfun) - current_function_returns_abnormally = 1; + current_function_returns_abnormally = 1; return build_min (THROW_EXPR, void_type_node, exp); } if (exp == null_node) - warning (0, "throwing NULL, which has integral, not pointer type"); - + warning ("throwing NULL, which has integral, not pointer type"); + if (exp != NULL_TREE) { if (!is_admissible_throw_operand (exp)) - return error_mark_node; + return error_mark_node; } if (! doing_eh (1)) @@ -634,7 +595,7 @@ build_throw (tree exp) } else if (really_overloaded_fn (fn)) { - error ("%qD should never be overloaded", fn); + error ("`%D' should never be overloaded", fn); return error_mark_node; } fn = OVL_CURRENT (fn); @@ -643,7 +604,6 @@ build_throw (tree exp) else if (exp) { tree throw_type; - tree temp_type; tree cleanup; tree object, ptr; tree tmp; @@ -658,7 +618,7 @@ build_throw (tree exp) tmp = build_function_type (void_type_node, tmp); cleanup_type = build_pointer_type (tmp); } - + fn = get_identifier ("__cxa_throw"); if (!get_global_value_if_present (fn, &fn)) { @@ -671,18 +631,10 @@ build_throw (tree exp) tmp = build_function_type (void_type_node, tmp); fn = push_throw_library_fn (fn, tmp); } - - /* [except.throw] - - A throw-expression initializes a temporary object, the type - of which is determined by removing any top-level - cv-qualifiers from the static type of the operand of throw - and adjusting the type from "array of T" or "function return - T" to "pointer to T" or "pointer to function returning T" - respectively. */ - temp_type = is_bitfield_expr_with_lowered_type (exp); - if (!temp_type) - temp_type = type_decays_to (TYPE_MAIN_VARIANT (TREE_TYPE (exp))); + + /* throw expression */ + /* First, decay it. */ + exp = decay_conversion (exp); /* OK, this is kind of wacky. The standard says that we call terminate when the exception handling mechanism, after @@ -698,70 +650,51 @@ build_throw (tree exp) matter, since it can't throw). */ /* Allocate the space for the exception. */ - allocate_expr = do_allocate_exception (temp_type); + allocate_expr = do_allocate_exception (TREE_TYPE (exp)); allocate_expr = get_target_expr (allocate_expr); ptr = TARGET_EXPR_SLOT (allocate_expr); - object = build_nop (build_pointer_type (temp_type), ptr); + object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr); object = build_indirect_ref (object, NULL); elided = (TREE_CODE (exp) == TARGET_EXPR); /* And initialize the exception object. */ - if (CLASS_TYPE_P (temp_type)) + exp = build_init (object, exp, LOOKUP_ONLYCONVERTING); + if (exp == error_mark_node) { - /* Call the copy constructor. */ - exp = (build_special_member_call - (object, complete_ctor_identifier, - build_tree_list (NULL_TREE, exp), - TREE_TYPE (object), - LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING)); - if (exp == error_mark_node) - { - error (" in thrown expression"); - return error_mark_node; - } + error (" in thrown expression"); + return error_mark_node; } - else - exp = build2 (INIT_EXPR, temp_type, object, - decay_conversion (exp)); /* Pre-evaluate the thrown expression first, since if we allocated the space first we would have to deal with cleaning it up if evaluating this expression throws. - The case where EXP the initializer is a cast or a function - returning a class is a bit of a grey area in the standard; it's - unclear whether or not it should be allowed to throw. We used to - say no, as that allowed us to optimize this case without worrying - about deallocating the exception object if it does. But that - conflicted with expectations (PR 13944) and the EDG compiler; now - we wrap the initialization in a TRY_CATCH_EXPR to call - do_free_exception rather than in a MUST_NOT_THROW_EXPR, for this - case only. - - BUT: Issue 475 may do away with this inconsistency by removing the - terminate() in this situation. - - Note that we don't check the return value from stabilize_init - because it will only return false in cases where elided is true, - and therefore we don't need to work around the failure to - preevaluate. */ + The case where EXP the initializer is a call to a constructor or a + function returning a class is a bit of a grey area in the + standard; it's unclear whether or not it should be allowed to + throw. We used to say no, as that allowed us to optimize this + case without worrying about deallocating the exception object if + it does. But that conflicted with expectations (PR 13944) and the + EDG compiler; now we wrap the initialization in a TRY_CATCH_EXPR + to call do_free_exception rather than in a MUST_NOT_THROW_EXPR, + for this case only. + + Note that we don't check the return value from stabilize_init + because it will only return false in cases where elided is true, + and therefore we don't need to work around the failure to + preevaluate. */ temp_expr = NULL_TREE; stabilize_init (exp, &temp_expr); - /* Wrap the initialization in a CLEANUP_POINT_EXPR so that cleanups - for temporaries within the initialization are run before the one - for the exception object, preserving LIFO order. */ - exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); - if (elided) - exp = build2 (TRY_CATCH_EXPR, void_type_node, exp, - do_free_exception (ptr)); + exp = build (TRY_CATCH_EXPR, void_type_node, exp, + do_free_exception (ptr)); else exp = build1 (MUST_NOT_THROW_EXPR, void_type_node, exp); /* Prepend the allocation. */ - exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); + exp = build (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); if (temp_expr) { /* Prepend the calculation of the throw expression. Also, force @@ -770,13 +703,13 @@ build_throw (tree exp) them in MUST_NOT_THROW_EXPR, since they are run after the exception object is initialized. */ walk_tree_without_duplicates (&temp_expr, wrap_cleanups_r, 0); - exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), temp_expr, exp); + exp = build (COMPOUND_EXPR, TREE_TYPE (exp), temp_expr, exp); exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp); } throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); - if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object))) + if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object))) { cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), complete_dtor_identifier, 0); @@ -787,7 +720,10 @@ build_throw (tree exp) cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup); } else - cleanup = build_int_cst (cleanup_type, 0); + { + cleanup = build_int_2 (0, 0); + TREE_TYPE (cleanup) = cleanup_type; + } tmp = tree_cons (NULL_TREE, cleanup, NULL_TREE); tmp = tree_cons (NULL_TREE, throw_type, tmp); @@ -796,7 +732,7 @@ build_throw (tree exp) tmp = build_function_call (fn, tmp); /* Tack on the initialization stuff. */ - exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); + exp = build (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); } else { @@ -811,7 +747,7 @@ build_throw (tree exp) } /* ??? Indicate that this function call allows exceptions of the type - of the enclosing catch block (if known). */ + of the enclosing catch block (if known). */ exp = build_function_call (fn, NULL_TREE); } @@ -829,22 +765,22 @@ static int complete_ptr_ref_or_void_ptr_p (tree type, tree from) { int is_ptr; - + /* Check complete. */ type = complete_type_or_else (type, from); if (!type) return 0; - + /* Or a pointer or ref to one, or cv void *. */ is_ptr = TREE_CODE (type) == POINTER_TYPE; if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE) { tree core = TREE_TYPE (type); - + if (is_ptr && VOID_TYPE_P (core)) - /* OK */; + /* OK */; else if (!complete_type_or_else (core, from)) - return 0; + return 0; } return 1; } @@ -859,22 +795,21 @@ is_admissible_throw_operand (tree expr) tree type = TREE_TYPE (expr); /* 15.1/4 [...] The type of the throw-expression shall not be an - incomplete type, or a pointer or a reference to an incomplete - type, other than void*, const void*, volatile void*, or - const volatile void*. Except for these restriction and the - restrictions on type matching mentioned in 15.3, the operand - of throw is treated exactly as a function argument in a call - (5.2.2) or the operand of a return statement. */ + incomplete type, or a pointer or a reference to an incomplete + type, other than void*, const void*, volatile void*, or + const volatile void*. Except for these restriction and the + restrictions on type matching mentioned in 15.3, the operand + of throw is treated exactly as a function argument in a call + (5.2.2) or the operand of a return statement. */ if (!complete_ptr_ref_or_void_ptr_p (type, expr)) return false; /* 10.4/3 An abstract class shall not be used as a parameter type, - as a function return type or as type of an explicit - conversion. */ + as a function return type or as type of an explicit + conversion. */ else if (CLASS_TYPE_P (type) && CLASSTYPE_PURE_VIRTUALS (type)) { - error ("expression %qE of abstract class type %qT cannot " - "be used in throw-expression", expr, type); + error ("expression '%E' of abstract class type '%T' cannot be used in throw-expression", expr, type); return false; } @@ -905,10 +840,7 @@ nothrow_libfn_p (tree fn) /* Can't be a C library function. */ return 0; - /* Being a C library function, DECL_ASSEMBLER_NAME == DECL_NAME - unless the system headers are playing rename tricks, and if - they are, we don't want to be confused by them. */ - id = DECL_NAME (fn); + id = DECL_ASSEMBLER_NAME (fn); return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id)); } @@ -942,57 +874,51 @@ can_convert_eh (tree to, tree from) return 0; } -/* Check whether any of the handlers in I are shadowed by another handler - accepting TYPE. Note that the shadowing may not be complete; even if - an exception of type B would be caught by a handler for A, there could - be a derived class C for which A is an ambiguous base but B is not, so - the handler for B would catch an exception of type C. */ +/* Check whether any of HANDLERS are shadowed by another handler accepting + TYPE. Note that the shadowing may not be complete; even if an exception + of type B would be caught by a handler for A, there could be a derived + class C for which A is an ambiguous base but B is not, so the handler + for B would catch an exception of type C. */ static void -check_handlers_1 (tree master, tree_stmt_iterator i) +check_handlers_1 (tree master, tree handlers) { tree type = TREE_TYPE (master); + tree handler; - for (; !tsi_end_p (i); tsi_next (&i)) - { - tree handler = tsi_stmt (i); - if (TREE_TYPE (handler) && can_convert_eh (type, TREE_TYPE (handler))) - { - warning (0, "%Hexception of type %qT will be caught", - EXPR_LOCUS (handler), TREE_TYPE (handler)); - warning (0, "%H by earlier handler for %qT", - EXPR_LOCUS (master), type); - break; - } - } + for (handler = handlers; handler; handler = TREE_CHAIN (handler)) + if (TREE_TYPE (handler) + && can_convert_eh (type, TREE_TYPE (handler))) + { + input_line = STMT_LINENO (handler); + warning ("exception of type `%T' will be caught", + TREE_TYPE (handler)); + input_line = STMT_LINENO (master); + warning (" by earlier handler for `%T'", type); + break; + } } -/* Given a STATEMENT_LIST of HANDLERs, make sure that they're OK. */ +/* Given a chain of HANDLERs, make sure that they're OK. */ void check_handlers (tree handlers) { - tree_stmt_iterator i; - - /* If we don't have a STATEMENT_LIST, then we've just got one - handler, and thus nothing to warn about. */ - if (TREE_CODE (handlers) != STATEMENT_LIST) - return; - - i = tsi_start (handlers); - if (!tsi_end_p (i)) - while (1) - { - tree handler = tsi_stmt (i); - tsi_next (&i); - - /* No more handlers; nothing to shadow. */ - if (tsi_end_p (i)) - break; - if (TREE_TYPE (handler) == NULL_TREE) - pedwarn ("%H%<...%> handler must be the last handler for" - " its try block", EXPR_LOCUS (handler)); - else - check_handlers_1 (handler, i); - } + tree handler; + int save_line = input_line; + + for (handler = handlers; handler; handler = TREE_CHAIN (handler)) + { + if (TREE_CHAIN (handler) == NULL_TREE) + /* No more handlers; nothing to shadow. */; + else if (TREE_TYPE (handler) == NULL_TREE) + { + input_line = STMT_LINENO (handler); + pedwarn + ("`...' handler must be the last handler for its try block"); + } + else + check_handlers_1 (handler, TREE_CHAIN (handler)); + } + input_line = save_line; } diff --git a/contrib/gcc/cp/ptree.c b/contrib/gcc/cp/ptree.c index 246e88b..057add6 100644 --- a/contrib/gcc/cp/ptree.c +++ b/contrib/gcc/cp/ptree.c @@ -1,6 +1,6 @@ /* Prints out trees in human readable form. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -17,9 +17,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +/* $FreeBSD$ */ #include "config.h" #include "system.h" @@ -28,6 +29,13 @@ Boston, MA 02110-1301, USA. */ #include "tree.h" #include "cp-tree.h" +#ifndef HOST_PTR_PRINTF_FORMAT +#define HOST_PTR_PRINTF_FORMAT HOST_PTR_PRINTF +#endif +#ifndef HOST_PTR_PRINTF_TYPE +#define HOST_PTR_PRINTF_TYPE (void *) +#endif + void cxx_print_decl (FILE *file, tree node, int indent) { @@ -41,22 +49,21 @@ cxx_print_decl (FILE *file, tree node, int indent) return; } - if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON) - || !DECL_LANG_SPECIFIC (node)) + if (!DECL_LANG_SPECIFIC (node)) return; indent_to (file, indent + 3); if (TREE_CODE (node) == FUNCTION_DECL && DECL_PENDING_INLINE_INFO (node)) - fprintf (file, " pending-inline-info %p", - (void *) DECL_PENDING_INLINE_INFO (node)); + fprintf (file, " pending-inline-info " HOST_PTR_PRINTF_FORMAT, + HOST_PTR_PRINTF_TYPE DECL_PENDING_INLINE_INFO (node)); if (TREE_CODE (node) == TYPE_DECL && DECL_SORTED_FIELDS (node)) - fprintf (file, " sorted-fields %p", - (void *) DECL_SORTED_FIELDS (node)); + fprintf (file, " sorted-fields " HOST_PTR_PRINTF_FORMAT, + HOST_PTR_PRINTF_TYPE DECL_SORTED_FIELDS (node)); if ((TREE_CODE (node) == FUNCTION_DECL || TREE_CODE (node) == VAR_DECL) && DECL_TEMPLATE_INFO (node)) - fprintf (file, " template-info %p", - (void *) DECL_TEMPLATE_INFO (node)); + fprintf (file, " template-info " HOST_PTR_PRINTF_FORMAT, + HOST_PTR_PRINTF_TYPE DECL_TEMPLATE_INFO (node)); } void @@ -101,6 +108,8 @@ cxx_print_type (FILE *file, tree node, int indent) fputs ( "needs-constructor", file); if (TYPE_HAS_NONTRIVIAL_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)) @@ -122,20 +131,19 @@ cxx_print_type (FILE *file, tree node, int indent) fputs (" delete[]", file); if (TYPE_HAS_ASSIGN_REF (node)) fputs (" this=(X&)", file); + if (TYPE_USES_MULTIPLE_INHERITANCE (node)) + fputs (" uses-multiple-inheritance", file); if (TREE_CODE (node) == RECORD_TYPE) { - if (TYPE_BINFO (node)) - fprintf (file, " n_parents=%d", - BINFO_N_BASE_BINFOS (TYPE_BINFO (node))); - else - fprintf (file, " no-binfo"); - + fprintf (file, " n_parents %d", CLASSTYPE_N_BASECLASSES (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); } } @@ -143,25 +151,22 @@ cxx_print_type (FILE *file, tree node, int indent) static void cxx_print_binding (FILE *stream, cxx_binding *binding, const char *prefix) { - fprintf (stream, "%s <%p>", - prefix, (void *) binding); + fprintf (stream, "%s <" HOST_PTR_PRINTF_FORMAT ">", + prefix, HOST_PTR_PRINTF_TYPE binding); } void cxx_print_identifier (FILE *file, tree node, int indent) { - if (indent == 0) - fprintf (file, " "); - else - indent_to (file, indent); + indent_to (file, indent); cxx_print_binding (file, IDENTIFIER_NAMESPACE_BINDINGS (node), "bindings"); - if (indent == 0) - fprintf (file, " "); - else - indent_to (file, indent); + print_node (file, "class", IDENTIFIER_CLASS_VALUE (node), indent + 4); + indent_to (file, indent); cxx_print_binding (file, IDENTIFIER_BINDING (node), "local bindings"); 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); } void @@ -169,12 +174,6 @@ cxx_print_xnode (FILE *file, tree node, int indent) { switch (TREE_CODE (node)) { - case BASELINK: - print_node (file, "functions", BASELINK_FUNCTIONS (node), indent + 4); - print_node (file, "binfo", BASELINK_BINFO (node), indent + 4); - print_node (file, "access_binfo", BASELINK_ACCESS_BINFO (node), - indent + 4); - break; case OVERLOAD: print_node (file, "function", OVL_FUNCTION (node), indent+4); print_node (file, "chain", TREE_CHAIN (node), indent+4); diff --git a/contrib/gcc/cppinit.c b/contrib/gcc/cppinit.c index 647fbbf..a713cea 100644 --- a/contrib/gcc/cppinit.c +++ b/contrib/gcc/cppinit.c @@ -19,6 +19,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $FreeBSD$ */ + #include "config.h" #include "system.h" #include "cpplib.h" diff --git a/contrib/gcc/dbxout.c b/contrib/gcc/dbxout.c index 5732427..b12ea5c 100644 --- a/contrib/gcc/dbxout.c +++ b/contrib/gcc/dbxout.c @@ -1,7 +1,6 @@ /* Output dbx-format symbol table information from GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -17,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ /* Output dbx-format symbol table data. @@ -80,7 +79,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "regs.h" #include "insn-config.h" #include "reload.h" -#include "output.h" +#include "output.h" /* ASM_OUTPUT_SOURCE_LINE may refer to sdb functions. */ #include "dbxout.h" #include "toplev.h" #include "tm_p.h" @@ -89,36 +88,28 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "function.h" #include "target.h" #include "langhooks.h" -#include "obstack.h" -#include "expr.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" #endif +#undef DBXOUT_DECR_NESTING #define DBXOUT_DECR_NESTING \ if (--debug_nesting == 0 && symbol_queue_index > 0) \ { emit_pending_bincls_if_required (); debug_flush_symbol_queue (); } +#undef DBXOUT_DECR_NESTING_AND_RETURN #define DBXOUT_DECR_NESTING_AND_RETURN(x) \ do {--debug_nesting; return (x);} while (0) #ifndef ASM_STABS_OP -# ifdef XCOFF_DEBUGGING_INFO -# define ASM_STABS_OP "\t.stabx\t" -# else -# define ASM_STABS_OP "\t.stabs\t" -# endif +#define ASM_STABS_OP "\t.stabs\t" #endif #ifndef ASM_STABN_OP #define ASM_STABN_OP "\t.stabn\t" #endif -#ifndef ASM_STABD_OP -#define ASM_STABD_OP "\t.stabd\t" -#endif - #ifndef DBX_TYPE_DECL_STABS_CODE #define DBX_TYPE_DECL_STABS_CODE N_LSYM #endif @@ -135,32 +126,24 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #define DBX_REGPARM_STABS_LETTER 'P' #endif -#ifndef NO_DBX_FUNCTION_END -#define NO_DBX_FUNCTION_END 0 +/* This is used for parameters passed by invisible reference in a register. */ +#ifndef GDB_INV_REF_REGPARM_STABS_LETTER +#define GDB_INV_REF_REGPARM_STABS_LETTER 'a' #endif -#ifndef NO_DBX_BNSYM_ENSYM -#define NO_DBX_BNSYM_ENSYM 0 +#ifndef DBX_MEMPARM_STABS_LETTER +#define DBX_MEMPARM_STABS_LETTER 'p' #endif -#ifndef NO_DBX_MAIN_SOURCE_DIRECTORY -#define NO_DBX_MAIN_SOURCE_DIRECTORY 0 -#endif - -#ifndef DBX_BLOCKS_FUNCTION_RELATIVE -#define DBX_BLOCKS_FUNCTION_RELATIVE 0 -#endif - -#ifndef DBX_LINES_FUNCTION_RELATIVE -#define DBX_LINES_FUNCTION_RELATIVE 0 -#endif - -#ifndef DBX_CONTIN_LENGTH -#define DBX_CONTIN_LENGTH 80 +#ifndef FILE_NAME_JOINER +#define FILE_NAME_JOINER "/" #endif -#ifndef DBX_CONTIN_CHAR -#define DBX_CONTIN_CHAR '\\' +/* GDB needs to know that the stabs were generated by GCC. We emit an + N_OPT stab at the beginning of the source file to indicate this. + The string is historical, and different on a very few targets. */ +#ifndef STABS_GCC_MARKER +#define STABS_GCC_MARKER "gcc2_compiled." #endif enum typestatus {TYPE_UNSEEN, TYPE_XREF, TYPE_DEFINED}; @@ -196,12 +179,6 @@ static GTY(()) int typevec_len; static GTY(()) int next_type_number; -/* The C front end may call dbxout_symbol before dbxout_init runs. - We save all such decls in this list and output them when we get - to dbxout_init. */ - -static GTY(()) tree preinit_symbols; - enum binclstatus {BINCL_NOT_REQUIRED, BINCL_PENDING, BINCL_PROCESSED}; /* When using N_BINCL in dbx output, each type number is actually a @@ -243,6 +220,13 @@ static GTY(()) int scope_labelno; static GTY(()) int dbxout_source_line_counter; +/* Nonzero if we have actually used any of the GDB extensions + to the debugging format. The idea is that we use them for the + first time only if there's a strong reason, but once we have done that, + we use them whenever convenient. */ + +static GTY(()) int have_used_extensions = 0; + /* Number for the next N_SOL filename stabs label. The number 0 is reserved for the N_SO filename stabs label. */ @@ -269,8 +253,12 @@ static int pending_bincls = 0; /* The original input file name. */ static const char *base_input_file; +/* Current working directory. */ + +static const char *cwd; + #ifdef DEBUG_SYMS_TEXT -#define FORCE_TEXT switch_to_section (current_function_section ()) +#define FORCE_TEXT function_section (current_function_decl); #else #define FORCE_TEXT #endif @@ -282,7 +270,7 @@ static const char *base_input_file; /* 1 if PARM is passed to this function in memory. */ #define PARM_PASSED_IN_MEMORY(PARM) \ - (MEM_P (DECL_INCOMING_RTL (PARM))) + (GET_CODE (DECL_INCOMING_RTL (PARM)) == MEM) /* A C expression for the integer offset value of an automatic variable (N_LSYM) having address X (an RTX). */ @@ -297,11 +285,46 @@ static const char *base_input_file; #define DEBUGGER_ARG_OFFSET(OFFSET, X) (OFFSET) #endif -/* This obstack holds the stab string currently being constructed. We - build it up here, then write it out, so we can split long lines up - properly (see dbxout_finish_complex_stabs). */ -static struct obstack stabstr_ob; -static size_t stabstr_last_contin_point; +/* Stream for writing to assembler file. */ + +static FILE *asmfile; + +/* These variables are for dbxout_symbol to communicate to + dbxout_finish_symbol. + current_sym_code is the symbol-type-code, a symbol N_... define in stab.h. + current_sym_value and current_sym_addr are two ways to address the + value to store in the symtab entry. + current_sym_addr if nonzero represents the value as an rtx. + If that is zero, current_sym_value is used. This is used + when the value is an offset (such as for auto variables, + register variables and parms). */ + +static STAB_CODE_TYPE current_sym_code; +static int current_sym_value; +static rtx current_sym_addr; + +/* Number of chars of symbol-description generated so far for the + current symbol. Used by CHARS and CONTIN. */ + +static int current_sym_nchars; + +/* Report having output N chars of the current symbol-description. */ + +#define CHARS(N) (current_sym_nchars += (N)) + +/* Break the current symbol-description, generating a continuation, + if it has become long. */ + +#ifndef DBX_CONTIN_LENGTH +#define DBX_CONTIN_LENGTH 80 +#endif + +#if DBX_CONTIN_LENGTH > 0 +#define CONTIN \ + do {if (current_sym_nchars > DBX_CONTIN_LENGTH) dbxout_continue ();} while (0) +#else +#define CONTIN do { } while (0) +#endif #ifdef DBX_USE_BINCL static void emit_bincl_stab (const char *c); @@ -310,35 +333,40 @@ static void emit_pending_bincls (void); static inline void emit_pending_bincls_if_required (void); static void dbxout_init (const char *); - static void dbxout_finish (const char *); static void dbxout_start_source_file (unsigned, const char *); static void dbxout_end_source_file (unsigned); static void dbxout_typedefs (tree); static void dbxout_type_index (tree); +#if DBX_CONTIN_LENGTH > 0 +static void dbxout_continue (void); +#endif static void dbxout_args (tree); static void dbxout_type_fields (tree); -static void dbxout_type_method_1 (tree); +static void dbxout_type_method_1 (tree, const char *); static void dbxout_type_methods (tree); static void dbxout_range_type (tree); static void dbxout_type (tree, int); static bool print_int_cst_bounds_in_octal_p (tree); +static void print_int_cst_octal (tree); +static void print_octal (unsigned HOST_WIDE_INT, int); +static void print_wide_int (HOST_WIDE_INT); static void dbxout_type_name (tree); static void dbxout_class_name_qualifiers (tree); static int dbxout_symbol_location (tree, tree, const char *, rtx); static void dbxout_symbol_name (tree, const char *, int); +static void dbxout_prepare_symbol (tree); +static void dbxout_finish_symbol (tree); static void dbxout_block (tree, int, tree); static void dbxout_global_decl (tree); -static void dbxout_type_decl (tree, int); static void dbxout_handle_pch (unsigned); /* The debug hooks structure. */ #if defined (DBX_DEBUGGING_INFO) static void dbxout_source_line (unsigned int, const char *); -static void dbxout_begin_prologue (unsigned int, const char *); -static void dbxout_source_file (const char *); -static void dbxout_function_end (tree); +static void dbxout_source_file (FILE *, const char *); +static void dbxout_function_end (void); static void dbxout_begin_function (tree); static void dbxout_begin_block (unsigned, unsigned); static void dbxout_end_block (unsigned, unsigned); @@ -354,28 +382,23 @@ const struct gcc_debug_hooks dbx_debug_hooks = dbxout_end_source_file, dbxout_begin_block, dbxout_end_block, - debug_true_tree, /* ignore_block */ - dbxout_source_line, /* source_line */ - dbxout_begin_prologue, /* begin_prologue */ - debug_nothing_int_charstar, /* end_prologue */ - debug_nothing_int_charstar, /* end_epilogue */ + debug_true_tree, /* ignore_block */ + dbxout_source_line, /* source_line */ + dbxout_source_line, /* begin_prologue: just output line info */ + debug_nothing_int_charstar, /* end_prologue */ + debug_nothing_int_charstar, /* end_epilogue */ #ifdef DBX_FUNCTION_FIRST dbxout_begin_function, #else - debug_nothing_tree, /* begin_function */ + debug_nothing_tree, /* begin_function */ #endif - debug_nothing_int, /* end_function */ + debug_nothing_int, /* end_function */ dbxout_function_decl, - dbxout_global_decl, /* global_decl */ - dbxout_type_decl, /* type_decl */ - debug_nothing_tree_tree, /* imported_module_or_decl */ - debug_nothing_tree, /* deferred_inline_function */ - debug_nothing_tree, /* outlining_inline_function */ - debug_nothing_rtx, /* label */ - dbxout_handle_pch, /* handle_pch */ - debug_nothing_rtx, /* var_location */ - debug_nothing_void, /* switch_text_section */ - 0 /* start_end_main_source_file */ + dbxout_global_decl, /* global_decl */ + debug_nothing_tree, /* deferred_inline_function */ + debug_nothing_tree, /* outlining_inline_function */ + debug_nothing_rtx, /* label */ + dbxout_handle_pch /* handle_pch */ }; #endif /* DBX_DEBUGGING_INFO */ @@ -390,591 +413,61 @@ const struct gcc_debug_hooks xcoff_debug_hooks = dbxout_end_source_file, xcoffout_begin_block, xcoffout_end_block, - debug_true_tree, /* ignore_block */ + debug_true_tree, /* ignore_block */ xcoffout_source_line, - xcoffout_begin_prologue, /* begin_prologue */ - debug_nothing_int_charstar, /* end_prologue */ + xcoffout_begin_prologue, /* begin_prologue */ + debug_nothing_int_charstar, /* end_prologue */ xcoffout_end_epilogue, - debug_nothing_tree, /* begin_function */ + debug_nothing_tree, /* begin_function */ xcoffout_end_function, - debug_nothing_tree, /* function_decl */ - dbxout_global_decl, /* global_decl */ - dbxout_type_decl, /* type_decl */ - debug_nothing_tree_tree, /* imported_module_or_decl */ - debug_nothing_tree, /* deferred_inline_function */ - debug_nothing_tree, /* outlining_inline_function */ - debug_nothing_rtx, /* label */ - dbxout_handle_pch, /* handle_pch */ - debug_nothing_rtx, /* var_location */ - debug_nothing_void, /* switch_text_section */ - 0 /* start_end_main_source_file */ + debug_nothing_tree, /* function_decl */ + dbxout_global_decl, /* global_decl */ + debug_nothing_tree, /* deferred_inline_function */ + debug_nothing_tree, /* outlining_inline_function */ + debug_nothing_rtx, /* label */ + dbxout_handle_pch /* handle_pch */ }; #endif /* XCOFF_DEBUGGING_INFO */ -/* Numeric formatting helper macro. Note that this does not handle - hexadecimal. */ -#define NUMBER_FMT_LOOP(P, NUM, BASE) \ - do \ - { \ - int digit = NUM % BASE; \ - NUM /= BASE; \ - *--P = digit + '0'; \ - } \ - while (NUM > 0) - -/* Utility: write a decimal integer NUM to asm_out_file. */ -void -dbxout_int (int num) -{ - char buf[64]; - char *p = buf + sizeof buf; - unsigned int unum; - - if (num == 0) - { - putc ('0', asm_out_file); - return; - } - if (num < 0) - { - putc ('-', asm_out_file); - unum = -num; - } - else - unum = num; - - NUMBER_FMT_LOOP (p, unum, 10); - - while (p < buf + sizeof buf) - { - putc (*p, asm_out_file); - p++; - } -} - - -/* Primitives for emitting simple stabs directives. All other stabs - routines should use these functions instead of directly emitting - stabs. They are exported because machine-dependent code may need - to invoke them, e.g. in a DBX_OUTPUT_* macro whose definition - forwards to code in CPU.c. */ - -/* The following functions should all be called immediately after one - of the dbxout_begin_stab* functions (below). They write out - various things as the value of a stab. */ - -/* Write out a literal zero as the value of a stab. */ -void -dbxout_stab_value_zero (void) -{ - fputs ("0\n", asm_out_file); -} - -/* Write out the label LABEL as the value of a stab. */ -void -dbxout_stab_value_label (const char *label) -{ - assemble_name (asm_out_file, label); - putc ('\n', asm_out_file); -} - -/* Write out the difference of two labels, LABEL - BASE, as the value - of a stab. */ -void -dbxout_stab_value_label_diff (const char *label, const char *base) -{ - assemble_name (asm_out_file, label); - putc ('-', asm_out_file); - assemble_name (asm_out_file, base); - putc ('\n', asm_out_file); -} - -/* Write out an internal label as the value of a stab, and immediately - emit that internal label. This should be used only when - dbxout_stabd will not work. STEM is the name stem of the label, - COUNTERP is a pointer to a counter variable which will be used to - guarantee label uniqueness. */ -void -dbxout_stab_value_internal_label (const char *stem, int *counterp) -{ - char label[100]; - int counter = counterp ? (*counterp)++ : 0; - - ASM_GENERATE_INTERNAL_LABEL (label, stem, counter); - dbxout_stab_value_label (label); - targetm.asm_out.internal_label (asm_out_file, stem, counter); -} - -/* Write out the difference between BASE and an internal label as the - value of a stab, and immediately emit that internal label. STEM and - COUNTERP are as for dbxout_stab_value_internal_label. */ -void -dbxout_stab_value_internal_label_diff (const char *stem, int *counterp, - const char *base) -{ - char label[100]; - int counter = counterp ? (*counterp)++ : 0; - - ASM_GENERATE_INTERNAL_LABEL (label, stem, counter); - dbxout_stab_value_label_diff (label, base); - targetm.asm_out.internal_label (asm_out_file, stem, counter); -} - -/* The following functions produce specific kinds of stab directives. */ - -/* Write a .stabd directive with type STYPE and desc SDESC to asm_out_file. */ -void -dbxout_stabd (int stype, int sdesc) -{ - fputs (ASM_STABD_OP, asm_out_file); - dbxout_int (stype); - fputs (",0,", asm_out_file); - dbxout_int (sdesc); - putc ('\n', asm_out_file); -} - -/* Write a .stabn directive with type STYPE. This function stops - short of emitting the value field, which is the responsibility of - the caller (normally it will be either a symbol or the difference - of two symbols). */ - -void -dbxout_begin_stabn (int stype) -{ - fputs (ASM_STABN_OP, asm_out_file); - dbxout_int (stype); - fputs (",0,0,", asm_out_file); -} - -/* Write a .stabn directive with type N_SLINE and desc LINE. As above, - the value field is the responsibility of the caller. */ -void -dbxout_begin_stabn_sline (int lineno) -{ - fputs (ASM_STABN_OP, asm_out_file); - dbxout_int (N_SLINE); - fputs (",0,", asm_out_file); - dbxout_int (lineno); - putc (',', asm_out_file); -} - -/* Begin a .stabs directive with string "", type STYPE, and desc and - other fields 0. The value field is the responsibility of the - caller. This function cannot be used for .stabx directives. */ -void -dbxout_begin_empty_stabs (int stype) -{ - fputs (ASM_STABS_OP, asm_out_file); - fputs ("\"\",", asm_out_file); - dbxout_int (stype); - fputs (",0,0,", asm_out_file); -} - -/* Begin a .stabs directive with string STR, type STYPE, and desc 0. - The value field is the responsibility of the caller. */ -void -dbxout_begin_simple_stabs (const char *str, int stype) -{ - fputs (ASM_STABS_OP, asm_out_file); - output_quoted_string (asm_out_file, str); - putc (',', asm_out_file); - dbxout_int (stype); - fputs (",0,0,", asm_out_file); -} - -/* As above but use SDESC for the desc field. */ -void -dbxout_begin_simple_stabs_desc (const char *str, int stype, int sdesc) -{ - fputs (ASM_STABS_OP, asm_out_file); - output_quoted_string (asm_out_file, str); - putc (',', asm_out_file); - dbxout_int (stype); - fputs (",0,", asm_out_file); - dbxout_int (sdesc); - putc (',', asm_out_file); -} - -/* The next set of functions are entirely concerned with production of - "complex" .stabs directives: that is, .stabs directives whose - strings have to be constructed piecemeal. dbxout_type, - dbxout_symbol, etc. use these routines heavily. The string is queued - up in an obstack, then written out by dbxout_finish_complex_stabs, which - is also responsible for splitting it up if it exceeds DBX_CONTIN_LENGTH. - (You might think it would be more efficient to go straight to stdio - when DBX_CONTIN_LENGTH is 0 (i.e. no length limit) but that turns - out not to be the case, and anyway this needs fewer #ifdefs.) */ - -/* Begin a complex .stabs directive. If we can, write the initial - ASM_STABS_OP to the asm_out_file. */ - -static void -dbxout_begin_complex_stabs (void) -{ - emit_pending_bincls_if_required (); - FORCE_TEXT; - fputs (ASM_STABS_OP, asm_out_file); - putc ('"', asm_out_file); - gcc_assert (stabstr_last_contin_point == 0); -} - -/* As above, but do not force text or emit pending bincls. This is - used by dbxout_symbol_location, which needs to do something else. */ -static void -dbxout_begin_complex_stabs_noforcetext (void) -{ - fputs (ASM_STABS_OP, asm_out_file); - putc ('"', asm_out_file); - gcc_assert (stabstr_last_contin_point == 0); -} - -/* Add CHR, a single character, to the string being built. */ -#define stabstr_C(chr) obstack_1grow (&stabstr_ob, chr) - -/* Add STR, a normal C string, to the string being built. */ -#define stabstr_S(str) obstack_grow (&stabstr_ob, str, strlen(str)) - -/* Add the text of ID, an IDENTIFIER_NODE, to the string being built. */ -#define stabstr_I(id) obstack_grow (&stabstr_ob, \ - IDENTIFIER_POINTER (id), \ - IDENTIFIER_LENGTH (id)) - -/* Add NUM, a signed decimal number, to the string being built. */ -static void -stabstr_D (HOST_WIDE_INT num) -{ - char buf[64]; - char *p = buf + sizeof buf; - unsigned int unum; - - if (num == 0) - { - stabstr_C ('0'); - return; - } - if (num < 0) - { - stabstr_C ('-'); - unum = -num; - } - else - unum = num; - - NUMBER_FMT_LOOP (p, unum, 10); - - obstack_grow (&stabstr_ob, p, (buf + sizeof buf) - p); -} - -/* Add NUM, an unsigned decimal number, to the string being built. */ -static void -stabstr_U (unsigned HOST_WIDE_INT num) -{ - char buf[64]; - char *p = buf + sizeof buf; - if (num == 0) - { - stabstr_C ('0'); - return; - } - NUMBER_FMT_LOOP (p, num, 10); - obstack_grow (&stabstr_ob, p, (buf + sizeof buf) - p); -} - -/* Add CST, an INTEGER_CST tree, to the string being built as an - unsigned octal number. This routine handles values which are - larger than a single HOST_WIDE_INT. */ -static void -stabstr_O (tree cst) -{ - unsigned HOST_WIDE_INT high = TREE_INT_CST_HIGH (cst); - unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (cst); - - char buf[128]; - char *p = buf + sizeof buf; - - /* GDB wants constants with no extra leading "1" bits, so - we need to remove any sign-extension that might be - present. */ - { - const unsigned int width = TYPE_PRECISION (TREE_TYPE (cst)); - if (width == HOST_BITS_PER_WIDE_INT * 2) - ; - else if (width > HOST_BITS_PER_WIDE_INT) - high &= (((HOST_WIDE_INT) 1 << (width - HOST_BITS_PER_WIDE_INT)) - 1); - else if (width == HOST_BITS_PER_WIDE_INT) - high = 0; - else - high = 0, low &= (((HOST_WIDE_INT) 1 << width) - 1); - } - - /* Leading zero for base indicator. */ - stabstr_C ('0'); - - /* If the value is zero, the base indicator will serve as the value - all by itself. */ - if (high == 0 && low == 0) - return; - - /* If the high half is zero, we need only print the low half normally. */ - if (high == 0) - NUMBER_FMT_LOOP (p, low, 8); - else - { - /* When high != 0, we need to print enough zeroes from low to - give the digits from high their proper place-values. Hence - NUMBER_FMT_LOOP cannot be used. */ - const int n_digits = HOST_BITS_PER_WIDE_INT / 3; - int i; - - for (i = 1; i <= n_digits; i++) - { - unsigned int digit = low % 8; - low /= 8; - *--p = '0' + digit; - } - - /* Octal digits carry exactly three bits of information. The - width of a HOST_WIDE_INT is not normally a multiple of three. - Therefore, the next digit printed probably needs to carry - information from both low and high. */ - if (HOST_BITS_PER_WIDE_INT % 3 != 0) - { - const int n_leftover_bits = HOST_BITS_PER_WIDE_INT % 3; - const int n_bits_from_high = 3 - n_leftover_bits; - - const unsigned HOST_WIDE_INT - low_mask = (((unsigned HOST_WIDE_INT)1) << n_leftover_bits) - 1; - const unsigned HOST_WIDE_INT - high_mask = (((unsigned HOST_WIDE_INT)1) << n_bits_from_high) - 1; - - unsigned int digit; - - /* At this point, only the bottom n_leftover_bits bits of low - should be set. */ - gcc_assert (!(low & ~low_mask)); - - digit = (low | ((high & high_mask) << n_leftover_bits)); - high >>= n_bits_from_high; - - *--p = '0' + digit; - } - - /* Now we can format high in the normal manner. However, if - the only bits of high that were set were handled by the - digit split between low and high, high will now be zero, and - we don't want to print extra digits in that case. */ - if (high) - NUMBER_FMT_LOOP (p, high, 8); - } - - obstack_grow (&stabstr_ob, p, (buf + sizeof buf) - p); -} - -/* Called whenever it is safe to break a stabs string into multiple - .stabs directives. If the current string has exceeded the limit - set by DBX_CONTIN_LENGTH, mark the current position in the buffer - as a continuation point by inserting DBX_CONTIN_CHAR (doubled if - it is a backslash) and a null character. */ -static inline void -stabstr_continue (void) -{ - if (DBX_CONTIN_LENGTH > 0 - && obstack_object_size (&stabstr_ob) - stabstr_last_contin_point - > DBX_CONTIN_LENGTH) - { - if (DBX_CONTIN_CHAR == '\\') - obstack_1grow (&stabstr_ob, '\\'); - obstack_1grow (&stabstr_ob, DBX_CONTIN_CHAR); - obstack_1grow (&stabstr_ob, '\0'); - stabstr_last_contin_point = obstack_object_size (&stabstr_ob); - } -} -#define CONTIN stabstr_continue () - -/* Macro subroutine of dbxout_finish_complex_stabs, which emits - all of the arguments to the .stabs directive after the string. - Overridden by xcoffout.h. CODE is the stabs code for this symbol; - LINE is the source line to write into the desc field (in extended - mode); SYM is the symbol itself. - - ADDR, LABEL, and NUMBER are three different ways to represent the - stabs value field. At most one of these should be nonzero. - - ADDR is used most of the time; it represents the value as an - RTL address constant. - - LABEL is used (currently) only for N_CATCH stabs; it represents - the value as a string suitable for assemble_name. - - NUMBER is used when the value is an offset from an implicit base - pointer (e.g. for a stack variable), or an index (e.g. for a - register variable). It represents the value as a decimal integer. */ - -#ifndef DBX_FINISH_STABS -#define DBX_FINISH_STABS(SYM, CODE, LINE, ADDR, LABEL, NUMBER) \ -do { \ - int line_ = use_gnu_debug_info_extensions ? LINE : 0; \ - \ - dbxout_int (CODE); \ - fputs (",0,", asm_out_file); \ - dbxout_int (line_); \ - putc (',', asm_out_file); \ - if (ADDR) \ - output_addr_const (asm_out_file, ADDR); \ - else if (LABEL) \ - assemble_name (asm_out_file, LABEL); \ - else \ - dbxout_int (NUMBER); \ - putc ('\n', asm_out_file); \ -} while (0) -#endif - -/* Finish the emission of a complex .stabs directive. When DBX_CONTIN_LENGTH - is zero, this has only to emit the close quote and the remainder of - the arguments. When it is nonzero, the string has been marshalled in - stabstr_ob, and this routine is responsible for breaking it up into - DBX_CONTIN_LENGTH-sized chunks. - - SYM is the DECL of the symbol under consideration; it is used only - for its DECL_SOURCE_LINE. The other arguments are all passed directly - to DBX_FINISH_STABS; see above for details. */ - -static void -dbxout_finish_complex_stabs (tree sym, STAB_CODE_TYPE code, - rtx addr, const char *label, int number) -{ - int line ATTRIBUTE_UNUSED; - char *str; - size_t len; - - line = sym ? DECL_SOURCE_LINE (sym) : 0; - if (DBX_CONTIN_LENGTH > 0) - { - char *chunk; - size_t chunklen; - - /* Nul-terminate the growing string, then get its size and - address. */ - obstack_1grow (&stabstr_ob, '\0'); - - len = obstack_object_size (&stabstr_ob); - chunk = str = XOBFINISH (&stabstr_ob, char *); - - /* Within the buffer are a sequence of NUL-separated strings, - each of which is to be written out as a separate stab - directive. */ - for (;;) - { - chunklen = strlen (chunk); - fwrite (chunk, 1, chunklen, asm_out_file); - fputs ("\",", asm_out_file); - - /* Must add an extra byte to account for the NUL separator. */ - chunk += chunklen + 1; - len -= chunklen + 1; - - /* Only put a line number on the last stab in the sequence. */ - DBX_FINISH_STABS (sym, code, len == 0 ? line : 0, - addr, label, number); - if (len == 0) - break; - - fputs (ASM_STABS_OP, asm_out_file); - putc ('"', asm_out_file); - } - stabstr_last_contin_point = 0; - } - else - { - /* No continuations - we can put the whole string out at once. - It is faster to augment the string with the close quote and - comma than to do a two-character fputs. */ - obstack_grow (&stabstr_ob, "\",", 2); - len = obstack_object_size (&stabstr_ob); - str = XOBFINISH (&stabstr_ob, char *); - - fwrite (str, 1, len, asm_out_file); - DBX_FINISH_STABS (sym, code, line, addr, label, number); - } - obstack_free (&stabstr_ob, str); -} - #if defined (DBX_DEBUGGING_INFO) - static void -dbxout_function_end (tree decl) +dbxout_function_end (void) { char lscope_label_name[100]; /* The Lscope label must be emitted even if we aren't doing anything else; dbxout_block needs it. */ - switch_to_section (function_section (current_function_decl)); - - /* Convert Lscope into the appropriate format for local labels in case + /* Convert Ltext into the appropriate format for local labels in case the system doesn't insert underscores in front of user generated labels. */ ASM_GENERATE_INTERNAL_LABEL (lscope_label_name, "Lscope", scope_labelno); - targetm.asm_out.internal_label (asm_out_file, "Lscope", scope_labelno); + (*targetm.asm_out.internal_label) (asmfile, "Lscope", scope_labelno); + scope_labelno++; /* The N_FUN tag at the end of the function is a GNU extension, which may be undesirable, and is unnecessary if we do not have named sections. */ if (!use_gnu_debug_info_extensions +#if defined(NO_DBX_FUNCTION_END) || NO_DBX_FUNCTION_END - || !targetm.have_named_sections - || DECL_IGNORED_P (decl)) +#endif + || !targetm.have_named_sections) return; /* By convention, GCC will mark the end of a function with an N_FUN symbol and an empty string. */ - if (flag_reorder_blocks_and_partition) - { - dbxout_begin_empty_stabs (N_FUN); - dbxout_stab_value_label_diff (cfun->hot_section_end_label, - cfun->hot_section_label); - dbxout_begin_empty_stabs (N_FUN); - dbxout_stab_value_label_diff (cfun->cold_section_end_label, - cfun->cold_section_label); - } - else - { - char begin_label[20]; - /* Reference current function start using LFBB. */ - ASM_GENERATE_INTERNAL_LABEL (begin_label, "LFBB", scope_labelno); - dbxout_begin_empty_stabs (N_FUN); - dbxout_stab_value_label_diff (lscope_label_name, begin_label); - } - - if (!NO_DBX_BNSYM_ENSYM && !flag_debug_only_used_symbols) - dbxout_stabd (N_ENSYM, 0); +#ifdef DBX_OUTPUT_NFUN + DBX_OUTPUT_NFUN (asmfile, lscope_label_name, current_function_decl); +#else + fprintf (asmfile, "%s\"\",%d,0,0,", ASM_STABS_OP, N_FUN); + assemble_name (asmfile, lscope_label_name); + putc ('-', asmfile); + assemble_name (asmfile, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); + fprintf (asmfile, "\n"); +#endif } #endif /* DBX_DEBUGGING_INFO */ -/* Get lang description for N_SO stab. */ -static unsigned int ATTRIBUTE_UNUSED -get_lang_number (void) -{ - const char *language_string = lang_hooks.name; - - if (strcmp (language_string, "GNU C") == 0) - return N_SO_C; - else if (strcmp (language_string, "GNU C++") == 0) - return N_SO_CC; - else if (strcmp (language_string, "GNU F77") == 0) - return N_SO_FORTRAN; - else if (strcmp (language_string, "GNU F95") == 0) - return N_SO_FORTRAN90; /* CHECKME */ - else if (strcmp (language_string, "GNU Pascal") == 0) - return N_SO_PASCAL; - else if (strcmp (language_string, "GNU Objective-C") == 0) - return N_SO_OBJC; - else if (strcmp (language_string, "GNU Objective-C++") == 0) - return N_SO_OBJCPLUS; - else - return 0; - -} - /* At the beginning of compilation, start writing the symbol table. Initialize `typevec' and output the standard data types of C. */ @@ -982,62 +475,59 @@ static void dbxout_init (const char *input_file_name) { char ltext_label_name[100]; - bool used_ltext_label_name = false; - tree syms = lang_hooks.decls.getdecls (); + tree syms = (*lang_hooks.decls.getdecls) (); + + asmfile = asm_out_file; typevec_len = 100; typevec = ggc_calloc (typevec_len, sizeof typevec[0]); - /* stabstr_ob contains one string, which will be just fine with - 1-byte alignment. */ - obstack_specify_allocation (&stabstr_ob, 0, 1, xmalloc, free); - /* Convert Ltext into the appropriate format for local labels in case the system doesn't insert underscores in front of user generated labels. */ ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0); /* Put the current working directory in an N_SO symbol. */ - if (use_gnu_debug_info_extensions && !NO_DBX_MAIN_SOURCE_DIRECTORY) + if (use_gnu_debug_info_extensions) { - static const char *cwd; - - if (!cwd) + if (!cwd && (cwd = get_src_pwd ()) + && (!*cwd || cwd[strlen (cwd) - 1] != '/')) + cwd = concat (cwd, FILE_NAME_JOINER, NULL); + if (cwd) { - cwd = get_src_pwd (); - if (cwd[0] == '\0') - cwd = "/"; - else if (!IS_DIR_SEPARATOR (cwd[strlen (cwd) - 1])) - cwd = concat (cwd, "/", NULL); - } #ifdef DBX_OUTPUT_MAIN_SOURCE_DIRECTORY - DBX_OUTPUT_MAIN_SOURCE_DIRECTORY (asm_out_file, cwd); + DBX_OUTPUT_MAIN_SOURCE_DIRECTORY (asmfile, cwd); #else /* no DBX_OUTPUT_MAIN_SOURCE_DIRECTORY */ - dbxout_begin_simple_stabs_desc (cwd, N_SO, get_lang_number ()); - dbxout_stab_value_label (ltext_label_name); - used_ltext_label_name = true; + fprintf (asmfile, "%s", ASM_STABS_OP); + output_quoted_string (asmfile, cwd); + fprintf (asmfile, ",%d,0,0,", N_SO); + assemble_name (asmfile, ltext_label_name); + fputc ('\n', asmfile); #endif /* no DBX_OUTPUT_MAIN_SOURCE_DIRECTORY */ + } } #ifdef DBX_OUTPUT_MAIN_SOURCE_FILENAME - DBX_OUTPUT_MAIN_SOURCE_FILENAME (asm_out_file, input_file_name); + DBX_OUTPUT_MAIN_SOURCE_FILENAME (asmfile, input_file_name); +#else /* no DBX_OUTPUT_MAIN_SOURCE_FILENAME */ + /* We include outputting `Ltext:' here, + because that gives you a way to override it. */ + /* Used to put `Ltext:' before the reference, but that loses on sun 4. */ + fprintf (asmfile, "%s", ASM_STABS_OP); + output_quoted_string (asmfile, input_file_name); + fprintf (asmfile, ",%d,0,0,", N_SO); + assemble_name (asmfile, ltext_label_name); + fputc ('\n', asmfile); + text_section (); + (*targetm.asm_out.internal_label) (asmfile, "Ltext", 0); +#endif /* no DBX_OUTPUT_MAIN_SOURCE_FILENAME */ + +#ifdef DBX_OUTPUT_GCC_MARKER + DBX_OUTPUT_GCC_MARKER (asmfile); #else - dbxout_begin_simple_stabs_desc (input_file_name, N_SO, get_lang_number ()); - dbxout_stab_value_label (ltext_label_name); - used_ltext_label_name = true; -#endif - - if (used_ltext_label_name) - { - switch_to_section (text_section); - targetm.asm_out.internal_label (asm_out_file, "Ltext", 0); - } - - /* Emit an N_OPT stab to indicate that this file was compiled by GCC. - The string used is historical. */ -#ifndef NO_DBX_GCC_MARKER - dbxout_begin_simple_stabs ("gcc2_compiled.", N_OPT); - dbxout_stab_value_zero (); + /* Emit an N_OPT stab to indicate that this file was compiled by GCC. */ + fprintf (asmfile, "%s\"%s\",%d,0,0,0\n", + ASM_STABS_OP, STABS_GCC_MARKER, N_OPT); #endif base_input_file = lastfile = input_file_name; @@ -1045,7 +535,7 @@ dbxout_init (const char *input_file_name) next_type_number = 1; #ifdef DBX_USE_BINCL - current_file = XNEW (struct dbx_file); + current_file = xmalloc (sizeof *current_file); current_file->next = NULL; current_file->file_number = 0; current_file->next_type_number = 1; @@ -1055,20 +545,22 @@ dbxout_init (const char *input_file_name) current_file->pending_bincl_name = NULL; #endif + /* Make sure that types `int' and `char' have numbers 1 and 2. + Definitions of other integer types will refer to those numbers. + (Actually it should no longer matter what their numbers are. + Also, if any types with tags have been defined, dbxout_symbol + will output them first, so the numbers won't be 1 and 2. That + happens in C++. So it's a good thing it should no longer matter). */ + +#ifdef DBX_OUTPUT_STANDARD_TYPES + DBX_OUTPUT_STANDARD_TYPES (syms); +#endif + /* Get all permanent types that have typedef names, and output them all, except for those already output. Some language front ends - put these declarations in the top-level scope; some do not; - the latter are responsible for calling debug_hooks->type_decl from - their record_builtin_type function. */ + put these declarations in the top-level scope; some do not. */ + dbxout_typedefs ((*lang_hooks.decls.builtin_type_decls) ()); dbxout_typedefs (syms); - - if (preinit_symbols) - { - tree t; - for (t = nreverse (preinit_symbols); t; t = TREE_CHAIN (t)) - dbxout_symbol (TREE_VALUE (t), 0); - preinit_symbols = 0; - } } /* Output any typedef names for types described by TYPE_DECLs in SYMS. */ @@ -1095,8 +587,9 @@ dbxout_typedefs (tree syms) static void emit_bincl_stab (const char *name) { - dbxout_begin_simple_stabs (name, N_BINCL); - dbxout_stab_value_zero (); + fprintf (asmfile, "%s", ASM_STABS_OP); + output_quoted_string (asmfile, name); + fprintf (asmfile, ",%d,0,0,0\n", N_BINCL); } /* If there are pending bincls then it is time to emit all of them. */ @@ -1154,7 +647,7 @@ dbxout_start_source_file (unsigned int line ATTRIBUTE_UNUSED, const char *filename ATTRIBUTE_UNUSED) { #ifdef DBX_USE_BINCL - struct dbx_file *n = XNEW (struct dbx_file); + struct dbx_file *n = xmalloc (sizeof *n); n->next = current_file; n->next_type_number = 1; @@ -1178,10 +671,7 @@ dbxout_end_source_file (unsigned int line ATTRIBUTE_UNUSED) #ifdef DBX_USE_BINCL /* Emit EINCL stab only if BINCL is not pending. */ if (current_file->bincl_status == BINCL_PROCESSED) - { - dbxout_begin_stabn (N_EINCL); - dbxout_stab_value_zero (); - } + fprintf (asmfile, "%s%d,0,0,0\n", ASM_STABN_OP, N_EINCL); current_file->bincl_status = BINCL_NOT_REQUIRED; current_file = current_file->next; #endif @@ -1216,7 +706,7 @@ dbxout_handle_pch (unsigned at_end) /* Output debugging info to FILE to switch to sourcefile FILENAME. */ static void -dbxout_source_file (const char *filename) +dbxout_source_file (FILE *file, const char *filename) { if (lastfile == 0 && lastfile_is_base) { @@ -1226,60 +716,39 @@ dbxout_source_file (const char *filename) if (filename && (lastfile == 0 || strcmp (filename, lastfile))) { - /* Don't change section amid function. */ - if (current_function_decl == NULL_TREE) - switch_to_section (text_section); - - dbxout_begin_simple_stabs (filename, N_SOL); - dbxout_stab_value_internal_label ("Ltext", &source_label_number); + char ltext_label_name[100]; + + ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", + source_label_number); + fprintf (file, "%s", ASM_STABS_OP); + output_quoted_string (file, filename); + fprintf (asmfile, ",%d,0,0,", N_SOL); + assemble_name (asmfile, ltext_label_name); + fputc ('\n', asmfile); + if (current_function_decl != NULL_TREE + && DECL_SECTION_NAME (current_function_decl) != NULL_TREE) + ; /* Don't change section amid function. */ + else + text_section (); + (*targetm.asm_out.internal_label) (file, "Ltext", source_label_number); + source_label_number++; lastfile = filename; } } -/* Output N_BNSYM, line number symbol entry, and local symbol at - function scope */ - -static void -dbxout_begin_prologue (unsigned int lineno, const char *filename) -{ - if (use_gnu_debug_info_extensions - && !NO_DBX_FUNCTION_END - && !NO_DBX_BNSYM_ENSYM - && !flag_debug_only_used_symbols) - dbxout_stabd (N_BNSYM, 0); - - /* pre-increment the scope counter */ - scope_labelno++; - - dbxout_source_line (lineno, filename); - /* Output function begin block at function scope, referenced - by dbxout_block, dbxout_source_line and dbxout_function_end. */ - emit_pending_bincls_if_required (); - targetm.asm_out.internal_label (asm_out_file, "LFBB", scope_labelno); -} - /* Output a line number symbol entry for source file FILENAME and line number LINENO. */ static void dbxout_source_line (unsigned int lineno, const char *filename) { - dbxout_source_file (filename); + dbxout_source_file (asmfile, filename); -#ifdef DBX_OUTPUT_SOURCE_LINE - DBX_OUTPUT_SOURCE_LINE (asm_out_file, lineno, dbxout_source_line_counter); +#ifdef ASM_OUTPUT_SOURCE_LINE + dbxout_source_line_counter += 1; + ASM_OUTPUT_SOURCE_LINE (asmfile, lineno, dbxout_source_line_counter); #else - if (DBX_LINES_FUNCTION_RELATIVE) - { - char begin_label[20]; - dbxout_begin_stabn_sline (lineno); - /* Reference current function start using LFBB. */ - ASM_GENERATE_INTERNAL_LABEL (begin_label, "LFBB", scope_labelno); - dbxout_stab_value_internal_label_diff ("LM", &dbxout_source_line_counter, - begin_label); - } - else - dbxout_stabd (N_SLINE, lineno); + fprintf (asmfile, "%s%d,0,%d\n", ASM_STABD_OP, N_SLINE, lineno); #endif } @@ -1289,7 +758,7 @@ static void dbxout_begin_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int n) { emit_pending_bincls_if_required (); - targetm.asm_out.internal_label (asm_out_file, "LBB", n); + (*targetm.asm_out.internal_label) (asmfile, "LBB", n); } /* Describe the end line-number of an internal block within a function. */ @@ -1298,7 +767,7 @@ static void dbxout_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int n) { emit_pending_bincls_if_required (); - targetm.asm_out.internal_label (asm_out_file, "LBE", n); + (*targetm.asm_out.internal_label) (asmfile, "LBE", n); } /* Output dbx data for a function definition. @@ -1315,7 +784,10 @@ dbxout_function_decl (tree decl) dbxout_begin_function (decl); #endif dbxout_block (DECL_INITIAL (decl), 0, DECL_ARGUMENTS (decl)); - dbxout_function_end (decl); +#ifdef DBX_OUTPUT_FUNCTION_END + DBX_OUTPUT_FUNCTION_END (asmfile, decl); +#endif + dbxout_function_end (); } #endif /* DBX_DEBUGGING_INFO */ @@ -1325,7 +797,9 @@ dbxout_function_decl (tree decl) static void dbxout_global_decl (tree decl) { - if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)) + if (TREE_CODE (decl) == VAR_DECL + && ! DECL_EXTERNAL (decl) + && DECL_RTL_SET_P (decl)) /* Not necessary? */ { int saved_tree_used = TREE_USED (decl); TREE_USED (decl) = 1; @@ -1334,29 +808,17 @@ dbxout_global_decl (tree decl) } } -/* This is just a function-type adapter; dbxout_symbol does exactly - what we want but returns an int. */ -static void -dbxout_type_decl (tree decl, int local) -{ - dbxout_symbol (decl, local); -} - /* At the end of compilation, finish writing the symbol table. - The default is to call debug_free_queue but do nothing else. */ + Unless you define DBX_OUTPUT_MAIN_SOURCE_FILE_END, the default is + to do nothing. */ static void dbxout_finish (const char *filename ATTRIBUTE_UNUSED) { #ifdef DBX_OUTPUT_MAIN_SOURCE_FILE_END - DBX_OUTPUT_MAIN_SOURCE_FILE_END (asm_out_file, filename); -#elif defined DBX_OUTPUT_NULL_N_SO_AT_MAIN_SOURCE_FILE_END - { - switch_to_section (text_section); - dbxout_begin_empty_stabs (N_SO); - dbxout_stab_value_internal_label ("Letext", 0); - } -#endif + DBX_OUTPUT_MAIN_SOURCE_FILE_END (asmfile, filename); +#endif /* DBX_OUTPUT_MAIN_SOURCE_FILE_END */ + debug_free_queue (); } @@ -1366,24 +828,37 @@ static void dbxout_type_index (tree type) { #ifndef DBX_USE_BINCL - stabstr_D (TYPE_SYMTAB_ADDRESS (type)); + fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type)); + CHARS (3); #else struct typeinfo *t = &typevec[TYPE_SYMTAB_ADDRESS (type)]; - stabstr_C ('('); - stabstr_D (t->file_number); - stabstr_C (','); - stabstr_D (t->type_number); - stabstr_C (')'); + fprintf (asmfile, "(%d,%d)", t->file_number, t->type_number); + CHARS (9); #endif } - - -/* Used in several places: evaluates to '0' for a private decl, - '1' for a protected decl, '2' for a public decl. */ -#define DECL_ACCESSIBILITY_CHAR(DECL) \ -(TREE_PRIVATE (DECL) ? '0' : TREE_PROTECTED (DECL) ? '1' : '2') +#if DBX_CONTIN_LENGTH > 0 +/* Continue a symbol-description that gets too big. + End one symbol table entry with a double-backslash + and start a new one, eventually producing something like + .stabs "start......\\",code,0,value + .stabs "...rest",code,0,value */ +static void +dbxout_continue (void) +{ + emit_pending_bincls_if_required (); +#ifdef DBX_CONTIN_CHAR + fprintf (asmfile, "%c", DBX_CONTIN_CHAR); +#else + fprintf (asmfile, "\\\\"); +#endif + dbxout_finish_symbol (NULL_TREE); + fprintf (asmfile, "%s\"", ASM_STABS_OP); + current_sym_nchars = 0; +} +#endif /* DBX_CONTIN_LENGTH > 0 */ + /* Subroutine of `dbxout_type'. Output the type fields of TYPE. This must be a separate function because anonymous unions require recursive calls. */ @@ -1397,21 +872,21 @@ dbxout_type_fields (tree type) field that we can support. */ for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) { - /* If one of the nodes is an error_mark or its type is then - return early. */ + + /* If on of the nodes is an error_mark or its type is then return early. */ if (tem == error_mark_node || TREE_TYPE (tem) == error_mark_node) return; /* Omit here local type decls until we know how to support them. */ if (TREE_CODE (tem) == TYPE_DECL - /* Omit here the nameless fields that are used to skip bits. */ - || DECL_IGNORED_P (tem) /* Omit fields whose position or size are variable or too large to represent. */ || (TREE_CODE (tem) == FIELD_DECL && (! host_integerp (bit_position (tem), 0) || ! DECL_SIZE (tem) - || ! host_integerp (DECL_SIZE (tem), 1)))) + || ! host_integerp (DECL_SIZE (tem), 1))) + /* Omit here the nameless fields that are used to skip bits. */ + || DECL_IGNORED_P (tem)) continue; else if (TREE_CODE (tem) != CONST_DECL) @@ -1422,15 +897,26 @@ dbxout_type_fields (tree type) CONTIN; if (DECL_NAME (tem)) - stabstr_I (DECL_NAME (tem)); - stabstr_C (':'); + { + fprintf (asmfile, "%s:", IDENTIFIER_POINTER (DECL_NAME (tem))); + CHARS (2 + IDENTIFIER_LENGTH (DECL_NAME (tem))); + } + else + { + fprintf (asmfile, ":"); + CHARS (1); + } if (use_gnu_debug_info_extensions && (TREE_PRIVATE (tem) || TREE_PROTECTED (tem) || TREE_CODE (tem) != FIELD_DECL)) { - stabstr_C ('/'); - stabstr_C (DECL_ACCESSIBILITY_CHAR (tem)); + have_used_extensions = 1; + putc ('/', asmfile); + putc ((TREE_PRIVATE (tem) ? '0' + : TREE_PROTECTED (tem) ? '1' : '2'), + asmfile); + CHARS (2); } dbxout_type ((TREE_CODE (tem) == FIELD_DECL @@ -1443,31 +929,37 @@ dbxout_type_fields (tree type) { tree name = DECL_ASSEMBLER_NAME (tem); - stabstr_C (':'); - stabstr_I (name); - stabstr_C (';'); + have_used_extensions = 1; + fprintf (asmfile, ":%s;", IDENTIFIER_POINTER (name)); + CHARS (IDENTIFIER_LENGTH (name) + 2); } else - /* If TEM is non-static, GDB won't understand it. */ - stabstr_S (",0,0;"); + { + /* If TEM is non-static, GDB won't understand it. */ + fprintf (asmfile, ",0,0;"); + CHARS (5); + } } else { - stabstr_C (','); - stabstr_D (int_bit_position (tem)); - stabstr_C (','); - stabstr_D (tree_low_cst (DECL_SIZE (tem), 1)); - stabstr_C (';'); + putc (',', asmfile); + print_wide_int (int_bit_position (tem)); + putc (',', asmfile); + print_wide_int (tree_low_cst (DECL_SIZE (tem), 1)); + putc (';', asmfile); + CHARS (3); } } } } /* Subroutine of `dbxout_type_methods'. Output debug info about the - method described DECL. */ + method described DECL. DEBUG_NAME is an encoding of the method's + type signature. ??? We may be able to do without DEBUG_NAME altogether + now. */ static void -dbxout_type_method_1 (tree decl) +dbxout_type_method_1 (tree decl, const char *debug_name) { char c1 = 'A', c2; @@ -1491,21 +983,20 @@ dbxout_type_method_1 (tree decl) c2 = '.'; } - /* ??? Output the mangled name, which contains an encoding of the - method's type signature. May not be necessary anymore. */ - stabstr_C (':'); - stabstr_I (DECL_ASSEMBLER_NAME (decl)); - stabstr_C (';'); - stabstr_C (DECL_ACCESSIBILITY_CHAR (decl)); - stabstr_C (c1); - stabstr_C (c2); + fprintf (asmfile, ":%s;%c%c%c", debug_name, + TREE_PRIVATE (decl) ? '0' + : TREE_PROTECTED (decl) ? '1' : '2', c1, c2); + CHARS (IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (decl)) + 6 + - (debug_name - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)))); if (DECL_VINDEX (decl) && host_integerp (DECL_VINDEX (decl), 0)) { - stabstr_D (tree_low_cst (DECL_VINDEX (decl), 0)); - stabstr_C (';'); + print_wide_int (tree_low_cst (DECL_VINDEX (decl), 0)); + putc (';', asmfile); + CHARS (1); dbxout_type (DECL_CONTEXT (decl), 0); - stabstr_C (';'); + fprintf (asmfile, ";"); + CHARS (1); } } @@ -1517,12 +1008,39 @@ dbxout_type_methods (tree type) { /* C++: put out the method names and their parameter lists */ tree methods = TYPE_METHODS (type); + tree type_encoding; tree fndecl; tree last; + char formatted_type_identifier_length[16]; + int type_identifier_length; if (methods == NULL_TREE) return; + type_encoding = DECL_NAME (TYPE_NAME (type)); + +#if 0 + /* C++: Template classes break some assumptions made by this code about + the class names, constructor names, and encodings for assembler + label names. For now, disable output of dbx info for them. */ + { + const char *ptr = IDENTIFIER_POINTER (type_encoding); + /* This should use index. (mrs) */ + while (*ptr && *ptr != '<') ptr++; + if (*ptr != 0) + { + static int warned; + if (!warned) + warned = 1; + return; + } + } +#endif + + type_identifier_length = IDENTIFIER_LENGTH (type_encoding); + + sprintf (formatted_type_identifier_length, "%d", type_identifier_length); + if (TREE_CODE (methods) != TREE_VEC) fndecl = methods; else if (TREE_VEC_ELT (methods, 0) != NULL_TREE) @@ -1543,12 +1061,18 @@ dbxout_type_methods (tree type) well as the name of the field before overloading, along with its parameter list */ { + /* This is the "mangled" name of the method. + It encodes the argument types. */ + const char *debug_name; + /* Skip methods that aren't FUNCTION_DECLs. (In C++, these include TEMPLATE_DECLs.) The debugger doesn't know what to do with such entities anyhow. */ if (TREE_CODE (fndecl) != FUNCTION_DECL) continue; + debug_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)); + CONTIN; last = fndecl; @@ -1562,16 +1086,21 @@ dbxout_type_methods (tree type) expects. */ if (need_prefix) { - stabstr_I (DECL_NAME (fndecl)); - stabstr_S ("::"); + tree name = DECL_NAME (fndecl); + fprintf (asmfile, "%s::", IDENTIFIER_POINTER (name)); + CHARS (IDENTIFIER_LENGTH (name) + 2); need_prefix = 0; } dbxout_type (TREE_TYPE (fndecl), 0); - dbxout_type_method_1 (fndecl); + + dbxout_type_method_1 (fndecl, debug_name); } if (!need_prefix) - stabstr_C (';'); + { + putc (';', asmfile); + CHARS (1); + } } } @@ -1582,7 +1111,7 @@ dbxout_type_methods (tree type) static void dbxout_range_type (tree type) { - stabstr_C ('r'); + fprintf (asmfile, "r"); if (TREE_TYPE (type)) dbxout_type (TREE_TYPE (type), 0); else if (TREE_CODE (type) != INTEGER_TYPE) @@ -1607,30 +1136,39 @@ dbxout_range_type (tree type) dbxout_type_index (integer_type_node); } - stabstr_C (';'); if (TYPE_MIN_VALUE (type) != 0 && host_integerp (TYPE_MIN_VALUE (type), 0)) { + putc (';', asmfile); + CHARS (1); if (print_int_cst_bounds_in_octal_p (type)) - stabstr_O (TYPE_MIN_VALUE (type)); + print_int_cst_octal (TYPE_MIN_VALUE (type)); else - stabstr_D (tree_low_cst (TYPE_MIN_VALUE (type), 0)); + print_wide_int (tree_low_cst (TYPE_MIN_VALUE (type), 0)); } else - stabstr_C ('0'); + { + fprintf (asmfile, ";0"); + CHARS (2); + } - stabstr_C (';'); if (TYPE_MAX_VALUE (type) != 0 && host_integerp (TYPE_MAX_VALUE (type), 0)) { + putc (';', asmfile); + CHARS (1); if (print_int_cst_bounds_in_octal_p (type)) - stabstr_O (TYPE_MAX_VALUE (type)); + print_int_cst_octal (TYPE_MAX_VALUE (type)); else - stabstr_D (tree_low_cst (TYPE_MAX_VALUE (type), 0)); - stabstr_C (';'); + print_wide_int (tree_low_cst (TYPE_MAX_VALUE (type), 0)); + putc (';', asmfile); + CHARS (1); } else - stabstr_S ("-1;"); + { + fprintf (asmfile, ";-1;"); + CHARS (4); + } } @@ -1650,15 +1188,11 @@ dbxout_type (tree type, int full) tree tem; tree main_variant; static int anonymous_type_number = 0; - bool vector_type = false; if (TREE_CODE (type) == VECTOR_TYPE) - { - /* The frontend feeds us a representation for the vector as a struct - containing an array. Pull out the array type. */ - type = TREE_TYPE (TYPE_FIELDS (TYPE_DEBUG_REPRESENTATION_TYPE (type))); - vector_type = true; - } + /* The frontend feeds us a representation for the vector as a struct + containing an array. Pull out the array type. */ + type = TREE_TYPE (TYPE_FIELDS (TYPE_DEBUG_REPRESENTATION_TYPE (type))); /* If there was an input error and we don't really have a type, avoid crashing and write something that is at least valid @@ -1716,7 +1250,7 @@ dbxout_type (tree type, int full) || TREE_CODE (type) == QUAL_UNION_TYPE || TREE_CODE (type) == ENUMERAL_TYPE) && TYPE_STUB_DECL (type) - && DECL_P (TYPE_STUB_DECL (type)) + && TREE_CODE_CLASS (TREE_CODE (TYPE_STUB_DECL (type))) == 'd' && ! DECL_IGNORED_P (TYPE_STUB_DECL (type))) debug_queue_symbol (TYPE_STUB_DECL (type)); else if (TYPE_NAME (type) @@ -1779,7 +1313,9 @@ dbxout_type (tree type, int full) #endif /* Output a definition now. */ - stabstr_C ('='); + + fprintf (asmfile, "="); + CHARS (1); /* Mark it as defined, so that if it is self-referent we will not get into an infinite recursion of definitions. */ @@ -1791,13 +1327,15 @@ dbxout_type (tree type, int full) cv-qualified types if we're using extensions. */ if (TYPE_READONLY (type) > TYPE_READONLY (main_variant)) { - stabstr_C ('k'); + putc ('k', asmfile); + CHARS (1); dbxout_type (build_type_variant (type, 0, TYPE_VOLATILE (type)), 0); return; } else if (TYPE_VOLATILE (type) > TYPE_VOLATILE (main_variant)) { - stabstr_C ('B'); + putc ('B', asmfile); + CHARS (1); dbxout_type (build_type_variant (type, TYPE_READONLY (type), 0), 0); return; } @@ -1825,7 +1363,7 @@ dbxout_type (tree type, int full) { case VOID_TYPE: case LANG_TYPE: - /* For a void type, just define it as itself; i.e., "5=5". + /* For a void type, just define it as itself; ie, "5=5". This makes us consider it defined without saying what it is. The debugger will make it a void type when the reference is seen, and nothing will @@ -1834,16 +1372,18 @@ dbxout_type (tree type, int full) break; case INTEGER_TYPE: - if (type == char_type_node && ! TYPE_UNSIGNED (type)) + if (type == char_type_node && ! TREE_UNSIGNED (type)) { /* Output the type `char' as a subrange of itself! I don't understand this definition, just copied it from the output of pcc. This used to use `r2' explicitly and we used to take care to make sure that `char' was type number 2. */ - stabstr_C ('r'); + fprintf (asmfile, "r"); + CHARS (1); dbxout_type_index (type); - stabstr_S (";0;127;"); + fprintf (asmfile, ";0;127;"); + CHARS (7); } /* If this is a subtype of another integer type, always prefer to @@ -1857,9 +1397,9 @@ dbxout_type (tree type, int full) if (use_gnu_debug_info_extensions && TYPE_PRECISION (type) != TYPE_PRECISION (integer_type_node)) { - stabstr_S ("@s"); - stabstr_D (TYPE_PRECISION (type)); - stabstr_C (';'); + have_used_extensions = 1; + fprintf (asmfile, "@s%d;", TYPE_PRECISION (type)); + CHARS (5); } dbxout_range_type (type); @@ -1873,14 +1413,15 @@ dbxout_type (tree type, int full) if (use_gnu_debug_info_extensions && TYPE_PRECISION (type) != TYPE_PRECISION (integer_type_node)) { - stabstr_S ("@s"); - stabstr_D (TYPE_PRECISION (type)); - stabstr_C (';'); + have_used_extensions = 1; + fprintf (asmfile, "@s%d;", TYPE_PRECISION (type)); + CHARS (5); } if (print_int_cst_bounds_in_octal_p (type)) { - stabstr_C ('r'); + fprintf (asmfile, "r"); + CHARS (1); /* If this type derives from another type, output type index of parent type. This is particularly important when parent type @@ -1892,11 +1433,14 @@ dbxout_type (tree type, int full) else dbxout_type_index (type); - stabstr_C (';'); - stabstr_O (TYPE_MIN_VALUE (type)); - stabstr_C (';'); - stabstr_O (TYPE_MAX_VALUE (type)); - stabstr_C (';'); + fprintf (asmfile, ";"); + CHARS (1); + print_int_cst_octal (TYPE_MIN_VALUE (type)); + fprintf (asmfile, ";"); + CHARS (1); + print_int_cst_octal (TYPE_MAX_VALUE (type)); + fprintf (asmfile, ";"); + CHARS (1); } else @@ -1909,22 +1453,59 @@ dbxout_type (tree type, int full) case REAL_TYPE: /* This used to say `r1' and we used to take care to make sure that `int' was type number 1. */ - stabstr_C ('r'); + fprintf (asmfile, "r"); + CHARS (1); dbxout_type_index (integer_type_node); - stabstr_C (';'); - stabstr_D (int_size_in_bytes (type)); - stabstr_S (";0;"); + putc (';', asmfile); + CHARS (1); + print_wide_int (int_size_in_bytes (type)); + fputs (";0;", asmfile); + CHARS (3); + break; + + case CHAR_TYPE: + if (use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + fputs ("@s", asmfile); + CHARS (2); + print_wide_int (BITS_PER_UNIT * int_size_in_bytes (type)); + fputs (";-20;", asmfile); + CHARS (4); + } + else + { + /* Output the type `char' as a subrange of itself. + That is what pcc seems to do. */ + fprintf (asmfile, "r"); + CHARS (1); + dbxout_type_index (char_type_node); + fprintf (asmfile, ";0;%d;", TREE_UNSIGNED (type) ? 255 : 127); + CHARS (7); + } break; case BOOLEAN_TYPE: if (use_gnu_debug_info_extensions) { - stabstr_S ("@s"); - stabstr_D (BITS_PER_UNIT * int_size_in_bytes (type)); - stabstr_S (";-16;"); + have_used_extensions = 1; + fputs ("@s", asmfile); + CHARS (2); + print_wide_int (BITS_PER_UNIT * int_size_in_bytes (type)); + fputs (";-16;", asmfile); + CHARS (4); } else /* Define as enumeral type (False, True) */ - stabstr_S ("eFalse:0,True:1,;"); + { + fprintf (asmfile, "eFalse:0,True:1,;"); + CHARS (17); + } + break; + + case FILE_TYPE: + putc ('d', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0); break; case COMPLEX_TYPE: @@ -1934,46 +1515,71 @@ dbxout_type (tree type, int full) if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE) { - stabstr_S ("R3;"); - stabstr_D (2 * int_size_in_bytes (TREE_TYPE (type))); - stabstr_S (";0;"); + fputs ("R3;", asmfile); + CHARS (3); + print_wide_int (2 * int_size_in_bytes (TREE_TYPE (type))); + fputs (";0;", asmfile); + CHARS (3); } else { /* Output a complex integer type as a structure, pending some other way to do it. */ - stabstr_C ('s'); - stabstr_D (int_size_in_bytes (type)); + putc ('s', asmfile); + CHARS (1); + print_wide_int (int_size_in_bytes (type)); + fprintf (asmfile, "real:"); + CHARS (5); - stabstr_S ("real:"); dbxout_type (TREE_TYPE (type), 0); - stabstr_S (",0,"); - stabstr_D (TYPE_PRECISION (TREE_TYPE (type))); - - stabstr_S (";imag:"); + fprintf (asmfile, ",0,%d;", TYPE_PRECISION (TREE_TYPE (type))); + CHARS (7); + fprintf (asmfile, "imag:"); + CHARS (5); dbxout_type (TREE_TYPE (type), 0); - stabstr_C (','); - stabstr_D (TYPE_PRECISION (TREE_TYPE (type))); - stabstr_C (','); - stabstr_D (TYPE_PRECISION (TREE_TYPE (type))); - stabstr_S (";;"); + fprintf (asmfile, ",%d,%d;;", TYPE_PRECISION (TREE_TYPE (type)), + TYPE_PRECISION (TREE_TYPE (type))); + CHARS (10); + } + break; + + case SET_TYPE: + if (use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + fputs ("@s", asmfile); + CHARS (2); + print_wide_int (BITS_PER_UNIT * int_size_in_bytes (type)); + putc (';', asmfile); + CHARS (1); + + /* Check if a bitstring type, which in Chill is + different from a [power]set. */ + if (TYPE_STRING_FLAG (type)) + { + fprintf (asmfile, "@S;"); + CHARS (3); + } } + putc ('S', asmfile); + CHARS (1); + dbxout_type (TYPE_DOMAIN (type), 0); break; case ARRAY_TYPE: /* Make arrays of packed bits look like bitstrings for chill. */ if (TYPE_PACKED (type) && use_gnu_debug_info_extensions) { - stabstr_S ("@s"); - stabstr_D (BITS_PER_UNIT * int_size_in_bytes (type)); - stabstr_S (";@S;S"); + have_used_extensions = 1; + fputs ("@s", asmfile); + CHARS (2); + print_wide_int (BITS_PER_UNIT * int_size_in_bytes (type)); + fprintf (asmfile, ";@S;S"); + CHARS (5); dbxout_type (TYPE_DOMAIN (type), 0); break; } - if (use_gnu_debug_info_extensions && vector_type) - stabstr_S ("@V;"); - /* Output "a" followed by a range type definition for the index type of the array followed by a reference to the target-type. @@ -1982,18 +1588,23 @@ dbxout_type (tree type, int full) different from an array of characters. */ if (TYPE_STRING_FLAG (type) && use_gnu_debug_info_extensions) { - stabstr_S ("@S;"); + have_used_extensions = 1; + fprintf (asmfile, "@S;"); + CHARS (3); } tem = TYPE_DOMAIN (type); if (tem == NULL) { - stabstr_S ("ar"); + fprintf (asmfile, "ar"); + CHARS (2); dbxout_type_index (integer_type_node); - stabstr_S (";0;-1;"); + fprintf (asmfile, ";0;-1;"); + CHARS (6); } else { - stabstr_C ('a'); + fprintf (asmfile, "a"); + CHARS (1); dbxout_range_type (tem); } @@ -2004,7 +1615,12 @@ dbxout_type (tree type, int full) case UNION_TYPE: case QUAL_UNION_TYPE: { - tree binfo = TYPE_BINFO (type); + int i, n_baseclasses = 0; + + if (TYPE_BINFO (type) != 0 + && TREE_CODE (TYPE_BINFO (type)) == TREE_VEC + && TYPE_BINFO_BASETYPES (type) != 0) + n_baseclasses = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)); /* Output a structure type. We must use the same test here as we use in the DBX_NO_XREFS case above. */ @@ -2023,83 +1639,93 @@ dbxout_type (tree type, int full) If the type has a name, don't nest its definition within another type's definition; instead, output an xref and let the definition come when the name is defined. */ - stabstr_S ((TREE_CODE (type) == RECORD_TYPE) ? "xs" : "xu"); + fputs ((TREE_CODE (type) == RECORD_TYPE) ? "xs" : "xu", asmfile); + CHARS (2); +#if 0 /* This assertion is legitimately false in C++. */ + /* We shouldn't be outputting a reference to a type before its + definition unless the type has a tag name. + A typedef name without a tag name should be impossible. */ + if (TREE_CODE (TYPE_NAME (type)) != IDENTIFIER_NODE) + abort (); +#endif if (TYPE_NAME (type) != 0) dbxout_type_name (type); else { - stabstr_S ("$$"); - stabstr_D (anonymous_type_number++); + fprintf (asmfile, "$$%d", anonymous_type_number++); + CHARS (5); } - stabstr_C (':'); + fprintf (asmfile, ":"); + CHARS (1); typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; break; } /* Identify record or union, and print its size. */ - stabstr_C ((TREE_CODE (type) == RECORD_TYPE) ? 's' : 'u'); - stabstr_D (int_size_in_bytes (type)); + putc (((TREE_CODE (type) == RECORD_TYPE) ? 's' : 'u'), asmfile); + CHARS (1); + print_wide_int (int_size_in_bytes (type)); - if (binfo) + if (use_gnu_debug_info_extensions) { - int i; - tree child; - VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (binfo); - - if (use_gnu_debug_info_extensions) + if (n_baseclasses) { - if (BINFO_N_BASE_BINFOS (binfo)) - { - stabstr_C ('!'); - stabstr_U (BINFO_N_BASE_BINFOS (binfo)); - stabstr_C (','); - } + have_used_extensions = 1; + fprintf (asmfile, "!%d,", n_baseclasses); + CHARS (8); } - for (i = 0; BINFO_BASE_ITERATE (binfo, i, child); i++) - { - tree access = (accesses ? VEC_index (tree, accesses, i) - : access_public_node); + } + for (i = 0; i < n_baseclasses; i++) + { + tree binfo = TYPE_BINFO (type); + tree child = BINFO_BASETYPE (binfo, i); + tree access = (BINFO_BASEACCESSES (binfo) + ? BINFO_BASEACCESS (binfo, i) : access_public_node); - if (use_gnu_debug_info_extensions) - { - stabstr_C (BINFO_VIRTUAL_P (child) ? '1' : '0'); - stabstr_C (access == access_public_node ? '2' : - access == access_protected_node - ? '1' :'0'); - if (BINFO_VIRTUAL_P (child) - && (strcmp (lang_hooks.name, "GNU C++") == 0 - || strcmp (lang_hooks.name, "GNU Objective-C++") == 0)) - /* For a virtual base, print the (negative) - offset within the vtable where we must look - to find the necessary adjustment. */ - stabstr_D - (tree_low_cst (BINFO_VPTR_FIELD (child), 0) - * BITS_PER_UNIT); - else - stabstr_D (tree_low_cst (BINFO_OFFSET (child), 0) - * BITS_PER_UNIT); - stabstr_C (','); - dbxout_type (BINFO_TYPE (child), 0); - stabstr_C (';'); - } + if (use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + putc (TREE_VIA_VIRTUAL (child) ? '1' : '0', asmfile); + putc (access == access_public_node ? '2' : + (access == access_protected_node ? '1' :'0'), + asmfile); + CHARS (2); + if (TREE_VIA_VIRTUAL (child) + && strcmp (lang_hooks.name, "GNU C++") == 0) + /* For a virtual base, print the (negative) offset within + the vtable where we must look to find the necessary + adjustment. */ + print_wide_int (tree_low_cst (BINFO_VPTR_FIELD (child), 0) + * BITS_PER_UNIT); else - { - /* Print out the base class information with - fields which have the same names at the types - they hold. */ - dbxout_type_name (BINFO_TYPE (child)); - stabstr_C (':'); - dbxout_type (BINFO_TYPE (child), full); - stabstr_C (','); - stabstr_D (tree_low_cst (BINFO_OFFSET (child), 0) - * BITS_PER_UNIT); - stabstr_C (','); - stabstr_D - (tree_low_cst (TYPE_SIZE (BINFO_TYPE (child)), 0) - * BITS_PER_UNIT); - stabstr_C (';'); - } + print_wide_int (tree_low_cst (BINFO_OFFSET (child), 0) + * BITS_PER_UNIT); + putc (',', asmfile); + CHARS (1); + dbxout_type (BINFO_TYPE (child), 0); + putc (';', asmfile); + CHARS (1); + } + else + { + /* Print out the base class information with fields + which have the same names at the types they hold. */ + dbxout_type_name (BINFO_TYPE (child)); + putc (':', asmfile); + CHARS (1); + dbxout_type (BINFO_TYPE (child), full); + putc (',', asmfile); + CHARS (1); + print_wide_int (tree_low_cst (BINFO_OFFSET (child), 0) + * BITS_PER_UNIT); + putc (',', asmfile); + CHARS (1); + print_wide_int (tree_low_cst (TYPE_SIZE (BINFO_TYPE (child)), + 0) + * BITS_PER_UNIT); + putc (';', asmfile); + CHARS (1); } } } @@ -2108,23 +1734,36 @@ dbxout_type (tree type, int full) dbxout_type_fields (type); if (use_gnu_debug_info_extensions && TYPE_METHODS (type) != NULL_TREE) { + have_used_extensions = 1; dbxout_type_methods (type); } - stabstr_C (';'); + putc (';', asmfile); + CHARS (1); if (use_gnu_debug_info_extensions && TREE_CODE (type) == RECORD_TYPE /* Avoid the ~ if we don't really need it--it confuses dbx. */ && TYPE_VFIELD (type)) { + have_used_extensions = 1; + + /* Tell GDB+ that it may keep reading. */ + putc ('~', asmfile); + CHARS (1); /* We need to write out info about what field this class uses as its "main" vtable pointer field, because if this field is inherited from a base class, GDB cannot necessarily figure out which field it's using in time. */ - stabstr_S ("~%"); - dbxout_type (DECL_FCONTEXT (TYPE_VFIELD (type)), 0); - stabstr_C (';'); + if (TYPE_VFIELD (type)) + { + putc ('%', asmfile); + CHARS (1); + dbxout_type (DECL_FCONTEXT (TYPE_VFIELD (type)), 0); + } + + putc (';', asmfile); + CHARS (1); } break; @@ -2138,58 +1777,66 @@ dbxout_type (tree type, int full) && !full) || !COMPLETE_TYPE_P (type)) { - stabstr_S ("xe"); + fprintf (asmfile, "xe"); + CHARS (2); dbxout_type_name (type); typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; - stabstr_C (':'); + putc (':', asmfile); + CHARS (1); return; } if (use_gnu_debug_info_extensions && TYPE_PRECISION (type) != TYPE_PRECISION (integer_type_node)) { - stabstr_S ("@s"); - stabstr_D (TYPE_PRECISION (type)); - stabstr_C (';'); + fprintf (asmfile, "@s%d;", TYPE_PRECISION (type)); + CHARS (5); } - stabstr_C ('e'); + putc ('e', asmfile); + CHARS (1); for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem)) { - stabstr_I (TREE_PURPOSE (tem)); - stabstr_C (':'); - + fprintf (asmfile, "%s:", IDENTIFIER_POINTER (TREE_PURPOSE (tem))); + CHARS (IDENTIFIER_LENGTH (TREE_PURPOSE (tem)) + 1); if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == 0) - stabstr_D (TREE_INT_CST_LOW (TREE_VALUE (tem))); + print_wide_int (TREE_INT_CST_LOW (TREE_VALUE (tem))); else if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == -1 && (HOST_WIDE_INT) TREE_INT_CST_LOW (TREE_VALUE (tem)) < 0) - stabstr_D (TREE_INT_CST_LOW (TREE_VALUE (tem))); + print_wide_int (TREE_INT_CST_LOW (TREE_VALUE (tem))); else - stabstr_O (TREE_VALUE (tem)); + print_int_cst_octal (TREE_VALUE (tem)); - stabstr_C (','); + putc (',', asmfile); + CHARS (1); if (TREE_CHAIN (tem) != 0) CONTIN; } - stabstr_C (';'); + putc (';', asmfile); + CHARS (1); break; case POINTER_TYPE: - stabstr_C ('*'); + putc ('*', asmfile); + CHARS (1); dbxout_type (TREE_TYPE (type), 0); break; case METHOD_TYPE: if (use_gnu_debug_info_extensions) { - stabstr_C ('#'); + have_used_extensions = 1; + putc ('#', asmfile); + CHARS (1); /* Write the argument types out longhand. */ dbxout_type (TYPE_METHOD_BASETYPE (type), 0); - stabstr_C (','); + putc (',', asmfile); + CHARS (1); dbxout_type (TREE_TYPE (type), 0); dbxout_args (TYPE_ARG_TYPES (type)); - stabstr_C (';'); + putc (';', asmfile); + CHARS (1); } else /* Treat it as a function type. */ @@ -2199,9 +1846,12 @@ dbxout_type (tree type, int full) case OFFSET_TYPE: if (use_gnu_debug_info_extensions) { - stabstr_C ('@'); + have_used_extensions = 1; + putc ('@', asmfile); + CHARS (1); dbxout_type (TYPE_OFFSET_BASETYPE (type), 0); - stabstr_C (','); + putc (',', asmfile); + CHARS (1); dbxout_type (TREE_TYPE (type), 0); } else @@ -2211,21 +1861,20 @@ dbxout_type (tree type, int full) case REFERENCE_TYPE: if (use_gnu_debug_info_extensions) - { - stabstr_C ('&'); - } - else - stabstr_C ('*'); + have_used_extensions = 1; + putc (use_gnu_debug_info_extensions ? '&' : '*', asmfile); + CHARS (1); dbxout_type (TREE_TYPE (type), 0); break; case FUNCTION_TYPE: - stabstr_C ('f'); + putc ('f', asmfile); + CHARS (1); dbxout_type (TREE_TYPE (type), 0); break; default: - gcc_unreachable (); + abort (); } } @@ -2253,199 +1902,145 @@ print_int_cst_bounds_in_octal_p (tree type) && TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST && (TYPE_PRECISION (type) > TYPE_PRECISION (integer_type_node) || ((TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) - && TYPE_UNSIGNED (type)) + && TREE_UNSIGNED (type)) || TYPE_PRECISION (type) > HOST_BITS_PER_WIDE_INT || (TYPE_PRECISION (type) == HOST_BITS_PER_WIDE_INT - && TYPE_UNSIGNED (type)))) + && TREE_UNSIGNED (type)))) return TRUE; else return FALSE; } -/* Output the name of type TYPE, with no punctuation. - Such names can be set up either by typedef declarations - or by struct, enum and union tags. */ +/* Print the value of integer constant C, in octal, + handling double precision. */ static void -dbxout_type_name (tree type) +print_int_cst_octal (tree c) { - tree t = TYPE_NAME (type); - - gcc_assert (t); - switch (TREE_CODE (t)) - { - case IDENTIFIER_NODE: - break; - case TYPE_DECL: - t = DECL_NAME (t); - break; - default: - gcc_unreachable (); - } - - stabstr_I (t); -} + unsigned HOST_WIDE_INT high = TREE_INT_CST_HIGH (c); + unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (c); + int excess = (3 - (HOST_BITS_PER_WIDE_INT % 3)); + unsigned int width = TYPE_PRECISION (TREE_TYPE (c)); -/* Output leading leading struct or class names needed for qualifying - type whose scope is limited to a struct or class. */ + /* GDB wants constants with no extra leading "1" bits, so + we need to remove any sign-extension that might be + present. */ + if (width == HOST_BITS_PER_WIDE_INT * 2) + ; + else if (width > HOST_BITS_PER_WIDE_INT) + high &= (((HOST_WIDE_INT) 1 << (width - HOST_BITS_PER_WIDE_INT)) - 1); + else if (width == HOST_BITS_PER_WIDE_INT) + high = 0; + else + high = 0, low &= (((HOST_WIDE_INT) 1 << width) - 1); -static void -dbxout_class_name_qualifiers (tree decl) -{ - tree context = decl_type_context (decl); + fprintf (asmfile, "0"); + CHARS (1); - if (context != NULL_TREE - && TREE_CODE(context) == RECORD_TYPE - && TYPE_NAME (context) != 0 - && (TREE_CODE (TYPE_NAME (context)) == IDENTIFIER_NODE - || (DECL_NAME (TYPE_NAME (context)) != 0))) + if (excess == 3) { - tree name = TYPE_NAME (context); - - if (TREE_CODE (name) == TYPE_DECL) - { - dbxout_class_name_qualifiers (name); - name = DECL_NAME (name); - } - stabstr_I (name); - stabstr_S ("::"); + print_octal (high, HOST_BITS_PER_WIDE_INT / 3); + print_octal (low, HOST_BITS_PER_WIDE_INT / 3); + } + else + { + unsigned HOST_WIDE_INT beg = high >> excess; + unsigned HOST_WIDE_INT middle + = ((high & (((HOST_WIDE_INT) 1 << excess) - 1)) << (3 - excess) + | (low >> (HOST_BITS_PER_WIDE_INT / 3 * 3))); + unsigned HOST_WIDE_INT end + = low & (((unsigned HOST_WIDE_INT) 1 + << (HOST_BITS_PER_WIDE_INT / 3 * 3)) + - 1); + + fprintf (asmfile, "%o%01o", (int) beg, (int) middle); + CHARS (2); + print_octal (end, HOST_BITS_PER_WIDE_INT / 3); } } - -/* This is a specialized subset of expand_expr for use by dbxout_symbol in - evaluating DECL_VALUE_EXPR. In particular, we stop if we find decls that - havn't been expanded, or if the expression is getting so complex we won't - be able to represent it in stabs anyway. Returns NULL on failure. */ -static rtx -dbxout_expand_expr (tree expr) +static void +print_octal (unsigned HOST_WIDE_INT value, int digits) { - switch (TREE_CODE (expr)) - { - case VAR_DECL: - case PARM_DECL: - if (DECL_HAS_VALUE_EXPR_P (expr)) - return dbxout_expand_expr (DECL_VALUE_EXPR (expr)); - /* FALLTHRU */ - - case CONST_DECL: - case RESULT_DECL: - return DECL_RTL_IF_SET (expr); - - case INTEGER_CST: - return expand_expr (expr, NULL_RTX, VOIDmode, EXPAND_INITIALIZER); + int i; - case COMPONENT_REF: - case ARRAY_REF: - case ARRAY_RANGE_REF: - case BIT_FIELD_REF: - { - enum machine_mode mode; - HOST_WIDE_INT bitsize, bitpos; - tree offset, tem; - int volatilep = 0, unsignedp = 0; - rtx x; - - tem = get_inner_reference (expr, &bitsize, &bitpos, &offset, - &mode, &unsignedp, &volatilep, true); - - x = dbxout_expand_expr (tem); - if (x == NULL || !MEM_P (x)) - return NULL; - if (offset != NULL) - { - if (!host_integerp (offset, 0)) - return NULL; - x = adjust_address_nv (x, mode, tree_low_cst (offset, 0)); - } - if (bitpos != 0) - x = adjust_address_nv (x, mode, bitpos / BITS_PER_UNIT); + for (i = digits - 1; i >= 0; i--) + fprintf (asmfile, "%01o", (int) ((value >> (3 * i)) & 7)); - return x; - } - - default: - return NULL; - } + CHARS (digits); } -/* Helper function for output_used_types. Queue one entry from the - used types hash to be output. */ +/* Output C in decimal while adjusting the number of digits written. */ -static int -output_used_types_helper (void **slot, void *data) +static void +print_wide_int (HOST_WIDE_INT c) { - tree type = *slot; - VEC(tree, heap) **types_p = data; + int digs = 0; - if ((TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE - || TREE_CODE (type) == ENUMERAL_TYPE) - && TYPE_STUB_DECL (type) - && DECL_P (TYPE_STUB_DECL (type)) - && ! DECL_IGNORED_P (TYPE_STUB_DECL (type))) - VEC_quick_push (tree, *types_p, TYPE_STUB_DECL (type)); - else if (TYPE_NAME (type) - && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) - VEC_quick_push (tree, *types_p, TYPE_NAME (type)); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, c); - return 1; + if (c < 0) + digs++, c = -c; + + while (c > 0) + c /= 10; digs++; + + CHARS (digs); } -/* This is a qsort callback which sorts types and declarations into a - predictable order (types, then declarations, sorted by UID - within). */ +/* Output the name of type TYPE, with no punctuation. + Such names can be set up either by typedef declarations + or by struct, enum and union tags. */ -static int -output_types_sort (const void *pa, const void *pb) +static void +dbxout_type_name (tree type) { - const tree lhs = *((const tree *)pa); - const tree rhs = *((const tree *)pb); - - if (TYPE_P (lhs)) + tree t; + if (TYPE_NAME (type) == 0) + abort (); + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) { - if (TYPE_P (rhs)) - return TYPE_UID (lhs) - TYPE_UID (rhs); - else - return 1; + t = TYPE_NAME (type); } - else + else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) { - if (TYPE_P (rhs)) - return -1; - else - return DECL_UID (lhs) - DECL_UID (rhs); + t = DECL_NAME (TYPE_NAME (type)); } -} + else + abort (); + fprintf (asmfile, "%s", IDENTIFIER_POINTER (t)); + CHARS (IDENTIFIER_LENGTH (t)); +} -/* Force all types used by this function to be output in debug - information. */ +/* Output leading leading struct or class names needed for qualifying + type whose scope is limited to a struct or class. */ static void -output_used_types (void) +dbxout_class_name_qualifiers (tree decl) { - if (cfun && cfun->used_types_hash) - { - VEC(tree, heap) *types; - int i; - tree type; - - types = VEC_alloc (tree, heap, htab_elements (cfun->used_types_hash)); - htab_traverse (cfun->used_types_hash, output_used_types_helper, &types); + tree context = decl_type_context (decl); - /* Sort by UID to prevent dependence on hash table ordering. */ - qsort (VEC_address (tree, types), VEC_length (tree, types), - sizeof (tree), output_types_sort); + if (context != NULL_TREE + && TREE_CODE(context) == RECORD_TYPE + && TYPE_NAME (context) != 0 + && (TREE_CODE (TYPE_NAME (context)) == IDENTIFIER_NODE + || (DECL_NAME (TYPE_NAME (context)) != 0))) + { + tree name = TYPE_NAME (context); - for (i = 0; VEC_iterate (tree, types, i, type); i++) - debug_queue_symbol (type); + emit_pending_bincls_if_required (); - VEC_free (tree, heap, types); + if (TREE_CODE (name) == TYPE_DECL) + { + dbxout_class_name_qualifiers (name); + name = DECL_NAME (name); + } + fprintf (asmfile, "%s::", IDENTIFIER_POINTER (name)); + CHARS (IDENTIFIER_LENGTH (name) + 2); } } - + /* Output a .stabs for the symbol defined by DECL, which must be a ..._DECL node in the normal namespace. It may be a CONST_DECL, a FUNCTION_DECL, a PARM_DECL or a VAR_DECL. @@ -2458,7 +2053,6 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) tree type = TREE_TYPE (decl); tree context = NULL_TREE; int result = 0; - rtx decl_rtl; /* "Intercept" dbxout_symbol() calls like we do all debug_hooks. */ ++debug_nesting; @@ -2470,30 +2064,22 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) DBXOUT_DECR_NESTING_AND_RETURN (0); /* If we are to generate only the symbols actually used then such - symbol nodes are flagged with TREE_USED. Ignore any that + symbol nodees are flagged with TREE_USED. Ignore any that aren't flaged as TREE_USED. */ - if (flag_debug_only_used_symbols - && (!TREE_USED (decl) - && (TREE_CODE (decl) != VAR_DECL || !DECL_INITIAL (decl)))) - DBXOUT_DECR_NESTING_AND_RETURN (0); - - /* If dbxout_init has not yet run, queue this symbol for later. */ - if (!typevec) - { - preinit_symbols = tree_cons (0, decl, preinit_symbols); - DBXOUT_DECR_NESTING_AND_RETURN (0); - } - if (flag_debug_only_used_symbols) { tree t; + if (!TREE_USED (decl) + && (TREE_CODE (decl) != VAR_DECL || !DECL_INITIAL (decl))) + DBXOUT_DECR_NESTING_AND_RETURN (0); + /* We now have a used symbol. We need to generate the info for the symbol's type in addition to the symbol itself. These type symbols are queued to be generated after were done with - the symbol itself (otherwise they would fight over the - stabstr obstack). + the symbol itself (done because the symbol's info is generated + with fprintf's, etc. as it determines what's needed). Note, because the TREE_TYPE(type) might be something like a pointer to a named type we need to look for the first name @@ -2510,32 +2096,38 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) a different name. In that case we also want to output that. */ - if (TREE_CODE (t) == RECORD_TYPE + if ((TREE_CODE (t) == RECORD_TYPE || TREE_CODE (t) == UNION_TYPE || TREE_CODE (t) == QUAL_UNION_TYPE || TREE_CODE (t) == ENUMERAL_TYPE) + && TYPE_STUB_DECL (t) + && TYPE_STUB_DECL (t) != decl + && TREE_CODE_CLASS (TREE_CODE (TYPE_STUB_DECL (t))) == 'd' + && ! DECL_IGNORED_P (TYPE_STUB_DECL (t))) { - if (TYPE_STUB_DECL (t) - && TYPE_STUB_DECL (t) != decl - && DECL_P (TYPE_STUB_DECL (t)) - && ! DECL_IGNORED_P (TYPE_STUB_DECL (t))) - { - debug_queue_symbol (TYPE_STUB_DECL (t)); - if (TYPE_NAME (t) - && TYPE_NAME (t) != TYPE_STUB_DECL (t) - && TYPE_NAME (t) != decl - && DECL_P (TYPE_NAME (t))) - debug_queue_symbol (TYPE_NAME (t)); - } - } + debug_queue_symbol (TYPE_STUB_DECL (t)); + if (TYPE_NAME (t) + && TYPE_NAME (t) != TYPE_STUB_DECL (t) + && TYPE_NAME (t) != decl + && TREE_CODE_CLASS (TREE_CODE (TYPE_NAME (t))) == 'd') + debug_queue_symbol (TYPE_NAME (t)); + } else if (TYPE_NAME (t) && TYPE_NAME (t) != decl - && DECL_P (TYPE_NAME (t))) + && TREE_CODE_CLASS (TREE_CODE (TYPE_NAME (t))) == 'd') debug_queue_symbol (TYPE_NAME (t)); } emit_pending_bincls_if_required (); + dbxout_prepare_symbol (decl); + + /* The output will always start with the symbol name, + so always count that in the length-output-so-far. */ + + if (DECL_NAME (decl) != 0) + current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (decl)); + switch (TREE_CODE (decl)) { case CONST_DECL: @@ -2543,8 +2135,7 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) break; case FUNCTION_DECL: - decl_rtl = DECL_RTL_IF_SET (decl); - if (!decl_rtl) + if (DECL_RTL (decl) == 0) DBXOUT_DECR_NESTING_AND_RETURN (0); if (DECL_EXTERNAL (decl)) break; @@ -2552,21 +2143,19 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) context = decl_function_context (decl); if (context == current_function_decl) break; - /* Don't mention an inline instance of a nested function. */ - if (context && DECL_FROM_INLINE (decl)) - break; - if (!MEM_P (decl_rtl) - || GET_CODE (XEXP (decl_rtl, 0)) != SYMBOL_REF) + if (GET_CODE (DECL_RTL (decl)) != MEM + || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF) break; + FORCE_TEXT; - if (flag_debug_only_used_symbols) - output_used_types (); - - dbxout_begin_complex_stabs (); - stabstr_I (DECL_ASSEMBLER_NAME (decl)); - stabstr_S (TREE_PUBLIC (decl) ? ":F" : ":f"); + fprintf (asmfile, "%s\"%s:%c", ASM_STABS_OP, + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), + TREE_PUBLIC (decl) ? 'F' : 'f'); result = 1; + current_sym_code = N_FUN; + current_sym_addr = XEXP (DECL_RTL (decl), 0); + if (TREE_TYPE (type)) dbxout_type (TREE_TYPE (type), 0); else @@ -2576,14 +2165,11 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) mention the containing function name as well as (since dbx wants it) our own assembler-name. */ if (context != 0) - { - stabstr_C (','); - stabstr_I (DECL_ASSEMBLER_NAME (decl)); - stabstr_C (','); - stabstr_I (DECL_NAME (context)); - } + fprintf (asmfile, ",%s,%s", + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), + IDENTIFIER_POINTER (DECL_NAME (context))); - dbxout_finish_complex_stabs (decl, N_FUN, XEXP (decl_rtl, 0), 0, 0); + dbxout_finish_symbol (decl); break; case TYPE_DECL: @@ -2592,20 +2178,6 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) if (TREE_ASM_WRITTEN (decl) || TYPE_DECL_SUPPRESS_DEBUG (decl)) DBXOUT_DECR_NESTING_AND_RETURN (0); - /* Don't output typedefs for types with magic type numbers (XCOFF). */ -#ifdef DBX_ASSIGN_FUNDAMENTAL_TYPE_NUMBER - { - int fundamental_type_number = - DBX_ASSIGN_FUNDAMENTAL_TYPE_NUMBER (decl); - - if (fundamental_type_number != 0) - { - TREE_ASM_WRITTEN (decl) = 1; - TYPE_SYMTAB_ADDRESS (TREE_TYPE (decl)) = fundamental_type_number; - DBXOUT_DECR_NESTING_AND_RETURN (0); - } - } -#endif FORCE_TEXT; result = 1; { @@ -2625,7 +2197,7 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) || TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == QUAL_UNION_TYPE) && TYPE_NAME (type) == decl - && !use_gnu_debug_info_extensions + && !(use_gnu_debug_info_extensions && have_used_extensions) && !TREE_ASM_WRITTEN (TYPE_NAME (type)) /* Distinguish the implicit typedefs of C++ from explicit ones that might be found in C. */ @@ -2641,23 +2213,28 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); - dbxout_begin_complex_stabs (); - stabstr_I (name); - stabstr_S (":T"); + current_sym_code = DBX_TYPE_DECL_STABS_CODE; + current_sym_value = 0; + current_sym_addr = 0; + current_sym_nchars = 2 + IDENTIFIER_LENGTH (name); + + fprintf (asmfile, "%s\"%s:T", ASM_STABS_OP, + IDENTIFIER_POINTER (name)); dbxout_type (type, 1); - dbxout_finish_complex_stabs (0, DBX_TYPE_DECL_STABS_CODE, - 0, 0, 0); + dbxout_finish_symbol (NULL_TREE); } - dbxout_begin_complex_stabs (); + /* Output .stabs (or whatever) and leading double quote. */ + fprintf (asmfile, "%s\"", ASM_STABS_OP); - /* Output leading class/struct qualifiers. */ if (use_gnu_debug_info_extensions) - dbxout_class_name_qualifiers (decl); + { + /* Output leading class/struct qualifiers. */ + dbxout_class_name_qualifiers (decl); + } /* Output typedef name. */ - stabstr_I (DECL_NAME (decl)); - stabstr_C (':'); + fprintf (asmfile, "%s:", IDENTIFIER_POINTER (DECL_NAME (decl))); /* Short cut way to output a tag also. */ if ((TREE_CODE (type) == RECORD_TYPE @@ -2668,17 +2245,22 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) from explicit ones that might be found in C. */ && DECL_ARTIFICIAL (decl)) { - if (use_gnu_debug_info_extensions) + if (use_gnu_debug_info_extensions && have_used_extensions) { - stabstr_C ('T'); + putc ('T', asmfile); TREE_ASM_WRITTEN (TYPE_NAME (type)) = 1; } +#if 0 /* Now we generate the tag for this case up above. */ + else + tag_needed = 1; +#endif } - stabstr_C ('t'); + putc ('t', asmfile); + current_sym_code = DBX_TYPE_DECL_STABS_CODE; + dbxout_type (type, 1); - dbxout_finish_complex_stabs (decl, DBX_TYPE_DECL_STABS_CODE, - 0, 0, 0); + dbxout_finish_symbol (decl); did_output = 1; } @@ -2700,26 +2282,33 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); - dbxout_begin_complex_stabs (); - stabstr_I (name); - stabstr_S (":T"); + current_sym_code = DBX_TYPE_DECL_STABS_CODE; + current_sym_value = 0; + current_sym_addr = 0; + current_sym_nchars = 2 + IDENTIFIER_LENGTH (name); + + fprintf (asmfile, "%s\"%s:T", ASM_STABS_OP, + IDENTIFIER_POINTER (name)); dbxout_type (type, 1); - dbxout_finish_complex_stabs (0, DBX_TYPE_DECL_STABS_CODE, 0, 0, 0); + dbxout_finish_symbol (NULL_TREE); did_output = 1; } - /* If an enum type has no name, it cannot be referred to, but - we must output it anyway, to record the enumeration - constants. */ - + /* If an enum type has no name, it cannot be referred to, + but we must output it anyway, since the enumeration constants + can be referred to. */ if (!did_output && TREE_CODE (type) == ENUMERAL_TYPE) { - dbxout_begin_complex_stabs (); + current_sym_code = DBX_TYPE_DECL_STABS_CODE; + current_sym_value = 0; + current_sym_addr = 0; + current_sym_nchars = 2; + /* Some debuggers fail when given NULL names, so give this a - harmless name of " " (Why not "(anon)"?). */ - stabstr_S (" :T"); + harmless name of ` '. */ + fprintf (asmfile, "%s\" :T", ASM_STABS_OP); dbxout_type (type, 1); - dbxout_finish_complex_stabs (0, DBX_TYPE_DECL_STABS_CODE, 0, 0, 0); + dbxout_finish_symbol (NULL_TREE); } /* Prevent duplicate output of a typedef. */ @@ -2730,59 +2319,58 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) case PARM_DECL: /* Parm decls go in their own separate chains and are output by dbxout_reg_parms and dbxout_parms. */ - gcc_unreachable (); + abort (); case RESULT_DECL: + /* Named return value, treat like a VAR_DECL. */ case VAR_DECL: + if (! DECL_RTL_SET_P (decl)) + DBXOUT_DECR_NESTING_AND_RETURN (0); /* Don't mention a variable that is external. Let the file that defines it describe it. */ if (DECL_EXTERNAL (decl)) break; /* If the variable is really a constant - and not written in memory, inform the debugger. - - ??? Why do we skip emitting the type and location in this case? */ + and not written in memory, inform the debugger. */ if (TREE_STATIC (decl) && TREE_READONLY (decl) && DECL_INITIAL (decl) != 0 && host_integerp (DECL_INITIAL (decl), 0) && ! TREE_ASM_WRITTEN (decl) && (DECL_CONTEXT (decl) == NULL_TREE - || TREE_CODE (DECL_CONTEXT (decl)) == BLOCK - || TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL) - && TREE_PUBLIC (decl) == 0) + || TREE_CODE (DECL_CONTEXT (decl)) == BLOCK)) { - /* The sun4 assembler does not grok this. */ - - if (TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE - || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) + if (TREE_PUBLIC (decl) == 0) { - HOST_WIDE_INT ival = TREE_INT_CST_LOW (DECL_INITIAL (decl)); - - dbxout_begin_complex_stabs (); - dbxout_symbol_name (decl, NULL, 'c'); - stabstr_S ("=i"); - stabstr_D (ival); - dbxout_finish_complex_stabs (0, N_LSYM, 0, 0, 0); - DBXOUT_DECR_NESTING; - return 1; + /* The sun4 assembler does not grok this. */ + const char *name = IDENTIFIER_POINTER (DECL_NAME (decl)); + + if (TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE + || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) + { + HOST_WIDE_INT ival = tree_low_cst (DECL_INITIAL (decl), 0); + fprintf (asmfile, "%s\"%s:c=i" HOST_WIDE_INT_PRINT_DEC + "\",0x%x,0,0,0\n", + ASM_STABS_OP, name, ival, N_LSYM); + DBXOUT_DECR_NESTING; + return 1; + } + else if (TREE_CODE (TREE_TYPE (decl)) == REAL_TYPE) + { + /* Don't know how to do this yet. */ + } + break; } - else - break; + /* else it is something we handle like a normal variable. */ } - /* else it is something we handle like a normal variable. */ - - decl_rtl = dbxout_expand_expr (decl); - if (!decl_rtl) - DBXOUT_DECR_NESTING_AND_RETURN (0); - decl_rtl = eliminate_regs (decl_rtl, 0, NULL_RTX); + SET_DECL_RTL (decl, eliminate_regs (DECL_RTL (decl), 0, NULL_RTX)); #ifdef LEAF_REG_REMAP if (current_function_uses_only_leaf_regs) - leaf_renumber_regs_insn (decl_rtl); + leaf_renumber_regs_insn (DECL_RTL (decl)); #endif - result = dbxout_symbol_location (decl, type, 0, decl_rtl); + result = dbxout_symbol_location (decl, type, 0, DECL_RTL (decl)); break; default: @@ -2802,11 +2390,10 @@ static int dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) { int letter = 0; - STAB_CODE_TYPE code; - rtx addr = 0; - int number = 0; int regno = -1; + emit_pending_bincls_if_required (); + /* Don't mention a variable at all if it was completely optimized into nothingness. @@ -2819,14 +2406,14 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) while (GET_CODE (value) == SUBREG) value = SUBREG_REG (value); - if (REG_P (value)) + if (GET_CODE (value) == REG) { if (REGNO (value) >= FIRST_PSEUDO_REGISTER) return 0; } home = alter_subreg (&home); } - if (REG_P (home)) + if (GET_CODE (home) == REG) { regno = REGNO (home); if (regno >= FIRST_PSEUDO_REGISTER) @@ -2846,16 +2433,17 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) no letter at all, and N_LSYM, for auto variable, r and N_RSYM for register variable. */ - if (MEM_P (home) && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) { if (TREE_PUBLIC (decl)) { letter = 'G'; - code = N_GSYM; + current_sym_code = N_GSYM; } else { - addr = XEXP (home, 0); + current_sym_addr = XEXP (home, 0); letter = decl_function_context (decl) ? 'V' : 'S'; @@ -2864,23 +2452,23 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) dumped into a constant pool. Alternatively, the symbol in the constant pool might be referenced by a different symbol. */ - if (GET_CODE (addr) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (addr)) + if (GET_CODE (current_sym_addr) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (current_sym_addr)) { bool marked; - rtx tmp = get_pool_constant_mark (addr, &marked); + rtx tmp = get_pool_constant_mark (current_sym_addr, &marked); if (GET_CODE (tmp) == SYMBOL_REF) { - addr = tmp; - if (CONSTANT_POOL_ADDRESS_P (addr)) - get_pool_constant_mark (addr, &marked); + current_sym_addr = tmp; + if (CONSTANT_POOL_ADDRESS_P (current_sym_addr)) + get_pool_constant_mark (current_sym_addr, &marked); else marked = true; } else if (GET_CODE (tmp) == LABEL_REF) { - addr = tmp; + current_sym_addr = tmp; marked = true; } @@ -2897,30 +2485,30 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) if (DECL_INITIAL (decl) == 0 || (!strcmp (lang_hooks.name, "GNU C++") && DECL_INITIAL (decl) == error_mark_node)) - code = N_LCSYM; + current_sym_code = N_LCSYM; else if (DECL_IN_TEXT_SECTION (decl)) /* This is not quite right, but it's the closest of all the codes that Unix defines. */ - code = DBX_STATIC_CONST_VAR_CODE; + current_sym_code = DBX_STATIC_CONST_VAR_CODE; else { /* Ultrix `as' seems to need this. */ #ifdef DBX_STATIC_STAB_DATA_SECTION - switch_to_section (data_section); + data_section (); #endif - code = N_STSYM; + current_sym_code = N_STSYM; } } } else if (regno >= 0) { letter = 'r'; - code = N_RSYM; - number = DBX_REGISTER_NUMBER (regno); + current_sym_code = N_RSYM; + current_sym_value = DBX_REGISTER_NUMBER (regno); } - else if (MEM_P (home) - && (MEM_P (XEXP (home, 0)) - || (REG_P (XEXP (home, 0)) + else if (GET_CODE (home) == MEM + && (GET_CODE (XEXP (home, 0)) == MEM + || (GET_CODE (XEXP (home, 0)) == REG && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM @@ -2932,22 +2520,24 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) then it means the object is variable-sized and address through that register or stack slot. DBX has no way to represent this so all we can do is output the variable as a pointer. - If it's not a parameter, ignore it. */ + If it's not a parameter, ignore it. + (VAR_DECLs like this can be made by integrate.c.) */ { - if (REG_P (XEXP (home, 0))) + if (GET_CODE (XEXP (home, 0)) == REG) { letter = 'r'; - code = N_RSYM; + current_sym_code = N_RSYM; if (REGNO (XEXP (home, 0)) >= FIRST_PSEUDO_REGISTER) return 0; - number = DBX_REGISTER_NUMBER (REGNO (XEXP (home, 0))); + current_sym_value = DBX_REGISTER_NUMBER (REGNO (XEXP (home, 0))); } else { - code = N_LSYM; + current_sym_code = N_LSYM; /* RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). We want the value of that CONST_INT. */ - number = DEBUGGER_AUTO_OFFSET (XEXP (XEXP (home, 0), 0)); + current_sym_value + = DEBUGGER_AUTO_OFFSET (XEXP (XEXP (home, 0), 0)); } /* Effectively do build_pointer_type, but don't cache this type, @@ -2957,22 +2547,22 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) type = make_node (POINTER_TYPE); TREE_TYPE (type) = TREE_TYPE (decl); } - else if (MEM_P (home) - && REG_P (XEXP (home, 0))) + else if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == REG) { - code = N_LSYM; - number = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); + current_sym_code = N_LSYM; + current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); } - else if (MEM_P (home) + else if (GET_CODE (home) == MEM && GET_CODE (XEXP (home, 0)) == PLUS && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) { - code = N_LSYM; + current_sym_code = N_LSYM; /* RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) We want the value of that CONST_INT. */ - number = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); + current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); } - else if (MEM_P (home) + else if (GET_CODE (home) == MEM && GET_CODE (XEXP (home, 0)) == CONST) { /* Handle an obscure case which can arise when optimizing and @@ -2986,9 +2576,9 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) variable, thereby avoiding the need for a register. In such cases we're forced to lie to debuggers and tell them that this variable was itself `static'. */ - code = N_LCSYM; + current_sym_code = N_LCSYM; letter = 'V'; - addr = XEXP (XEXP (home, 0), 0); + current_sym_addr = XEXP (XEXP (home, 0), 0); } else if (GET_CODE (home) == CONCAT) { @@ -3009,6 +2599,8 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) else dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 0)); + dbxout_prepare_symbol (decl); + if (WORDS_BIG_ENDIAN) dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 1)); else @@ -3022,20 +2614,18 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) return 0; /* Ok, start a symtab entry and output the variable name. */ - emit_pending_bincls_if_required (); FORCE_TEXT; #ifdef DBX_STATIC_BLOCK_START - DBX_STATIC_BLOCK_START (asm_out_file, code); + DBX_STATIC_BLOCK_START (asmfile, current_sym_code); #endif - dbxout_begin_complex_stabs_noforcetext (); dbxout_symbol_name (decl, suffix, letter); dbxout_type (type, 0); - dbxout_finish_complex_stabs (decl, code, addr, 0, number); + dbxout_finish_symbol (decl); #ifdef DBX_STATIC_BLOCK_END - DBX_STATIC_BLOCK_END (asm_out_file, code); + DBX_STATIC_BLOCK_END (asmfile, current_sym_code); #endif return 1; } @@ -3046,7 +2636,7 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) static void dbxout_symbol_name (tree decl, const char *suffix, int letter) { - tree name; + const char *name; if (DECL_CONTEXT (decl) && (TYPE_P (DECL_CONTEXT (decl)) @@ -3055,22 +2645,56 @@ dbxout_symbol_name (tree decl, const char *suffix, int letter) or a namespace member, we must put out the mangled name instead of the DECL_NAME. Note also that static member (variable) names DO NOT begin with underscores in .stabs directives. */ - name = DECL_ASSEMBLER_NAME (decl); + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); else /* ...but if we're function-local, we don't want to include the junk added by ASM_FORMAT_PRIVATE_NAME. */ - name = DECL_NAME (decl); + name = IDENTIFIER_POINTER (DECL_NAME (decl)); - if (name) - stabstr_I (name); - else - stabstr_S ("(anon)"); + if (name == 0) + name = "(anon)"; + fprintf (asmfile, "%s\"%s%s:", ASM_STABS_OP, name, + (suffix ? suffix : "")); - if (suffix) - stabstr_S (suffix); - stabstr_C (':'); if (letter) - stabstr_C (letter); + putc (letter, asmfile); +} + +static void +dbxout_prepare_symbol (tree decl ATTRIBUTE_UNUSED) +{ +#ifdef WINNING_GDB + const char *filename = DECL_SOURCE_FILE (decl); + + dbxout_source_file (asmfile, filename); +#endif + + /* Initialize variables used to communicate each symbol's debug + information to dbxout_finish_symbol with zeroes. */ + + /* Cast avoids warning in old compilers. */ + current_sym_code = (STAB_CODE_TYPE) 0; + current_sym_value = 0; + current_sym_addr = 0; +} + +static void +dbxout_finish_symbol (tree sym) +{ +#ifdef DBX_FINISH_SYMBOL + DBX_FINISH_SYMBOL (sym); +#else + int line = 0; + if (use_gnu_debug_info_extensions && sym != 0) + line = DECL_SOURCE_LINE (sym); + + fprintf (asmfile, "\",%d,0,%d,", current_sym_code, line); + if (current_sym_addr) + output_addr_const (asmfile, current_sym_addr); + else + fprintf (asmfile, "%d", current_sym_value); + putc ('\n', asmfile); +#endif } /* Output definitions of all the decls in a chain. Return nonzero if @@ -3104,18 +2728,13 @@ void dbxout_parms (tree parms) { ++debug_nesting; + emit_pending_bincls_if_required (); for (; parms; parms = TREE_CHAIN (parms)) - if (DECL_NAME (parms) - && TREE_TYPE (parms) != error_mark_node - && DECL_RTL_SET_P (parms) - && DECL_INCOMING_RTL (parms)) + if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) { - tree eff_type; - char letter; - STAB_CODE_TYPE code; - int number; + dbxout_prepare_symbol (parms); /* Perform any necessary register eliminations on the parameter's rtl, so that the debugging output will be accurate. */ @@ -3132,63 +2751,107 @@ dbxout_parms (tree parms) if (PARM_PASSED_IN_MEMORY (parms)) { - rtx inrtl = XEXP (DECL_INCOMING_RTL (parms), 0); + rtx addr = XEXP (DECL_INCOMING_RTL (parms), 0); /* ??? Here we assume that the parm address is indexed off the frame pointer or arg pointer. If that is not true, we produce meaningless results, but do not crash. */ - if (GET_CODE (inrtl) == PLUS - && GET_CODE (XEXP (inrtl, 1)) == CONST_INT) - number = INTVAL (XEXP (inrtl, 1)); + if (GET_CODE (addr) == PLUS + && GET_CODE (XEXP (addr, 1)) == CONST_INT) + current_sym_value = INTVAL (XEXP (addr, 1)); + else + current_sym_value = 0; + + current_sym_code = N_PSYM; + current_sym_addr = 0; + + FORCE_TEXT; + if (DECL_NAME (parms)) + { + current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms)); + + fprintf (asmfile, "%s\"%s:%c", ASM_STABS_OP, + IDENTIFIER_POINTER (DECL_NAME (parms)), + DBX_MEMPARM_STABS_LETTER); + } else - number = 0; - - code = N_PSYM; - number = DEBUGGER_ARG_OFFSET (number, inrtl); - letter = 'p'; - - /* It is quite tempting to use TREE_TYPE (parms) instead - of DECL_ARG_TYPE (parms) for the eff_type, so that gcc - reports the actual type of the parameter, rather than - the promoted type. This certainly makes GDB's life - easier, at least for some ports. The change is a bad - idea however, since GDB expects to be able access the - type without performing any conversions. So for - example, if we were passing a float to an unprototyped - function, gcc will store a double on the stack, but if - we emit a stab saying the type is a float, then gdb - will only read in a single value, and this will produce - an erroneous value. */ - eff_type = DECL_ARG_TYPE (parms); + { + current_sym_nchars = 8; + fprintf (asmfile, "%s\"(anon):%c", ASM_STABS_OP, + DBX_MEMPARM_STABS_LETTER); + } + + /* It is quite tempting to use: + + dbxout_type (TREE_TYPE (parms), 0); + + as the next statement, rather than using DECL_ARG_TYPE(), so + that gcc reports the actual type of the parameter, rather + than the promoted type. This certainly makes GDB's life + easier, at least for some ports. The change is a bad idea + however, since GDB expects to be able access the type without + performing any conversions. So for example, if we were + passing a float to an unprototyped function, gcc will store a + double on the stack, but if we emit a stab saying the type is a + float, then gdb will only read in a single value, and this will + produce an erroneous value. */ + dbxout_type (DECL_ARG_TYPE (parms), 0); + current_sym_value = DEBUGGER_ARG_OFFSET (current_sym_value, addr); + dbxout_finish_symbol (parms); } - else if (REG_P (DECL_RTL (parms))) + else if (GET_CODE (DECL_RTL (parms)) == REG) { rtx best_rtl; - + char regparm_letter; + tree parm_type; /* Parm passed in registers and lives in registers or nowhere. */ - code = DBX_REGPARM_STABS_CODE; - letter = DBX_REGPARM_STABS_LETTER; - - /* For parms passed in registers, it is better to use the - declared type of the variable, not the type it arrived in. */ - eff_type = TREE_TYPE (parms); - - /* If parm lives in a register, use that register; pretend - the parm was passed there. It would be more consistent - to describe the register where the parm was passed, but - in practice that register usually holds something else. - If the parm lives nowhere, use the register where it - was passed. */ + + current_sym_code = DBX_REGPARM_STABS_CODE; + regparm_letter = DBX_REGPARM_STABS_LETTER; + current_sym_addr = 0; + + /* If parm lives in a register, use that register; + pretend the parm was passed there. It would be more consistent + to describe the register where the parm was passed, + but in practice that register usually holds something else. + + If we use DECL_RTL, then we must use the declared type of + the variable, not the type that it arrived in. */ if (REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) - best_rtl = DECL_RTL (parms); + { + best_rtl = DECL_RTL (parms); + parm_type = TREE_TYPE (parms); + } + /* If the parm lives nowhere, use the register where it was + passed. It is also better to use the declared type here. */ else - best_rtl = DECL_INCOMING_RTL (parms); + { + best_rtl = DECL_INCOMING_RTL (parms); + parm_type = TREE_TYPE (parms); + } + current_sym_value = DBX_REGISTER_NUMBER (REGNO (best_rtl)); + + FORCE_TEXT; + if (DECL_NAME (parms)) + { + current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms)); + fprintf (asmfile, "%s\"%s:%c", ASM_STABS_OP, + IDENTIFIER_POINTER (DECL_NAME (parms)), + regparm_letter); + } + else + { + current_sym_nchars = 8; + fprintf (asmfile, "%s\"(anon):%c", ASM_STABS_OP, + regparm_letter); + } - number = DBX_REGISTER_NUMBER (REGNO (best_rtl)); + dbxout_type (parm_type, 0); + dbxout_finish_symbol (parms); } - else if (MEM_P (DECL_RTL (parms)) - && REG_P (XEXP (DECL_RTL (parms), 0)) + else if (GET_CODE (DECL_RTL (parms)) == MEM + && GET_CODE (XEXP (DECL_RTL (parms), 0)) == REG && REGNO (XEXP (DECL_RTL (parms), 0)) != HARD_FRAME_POINTER_REGNUM && REGNO (XEXP (DECL_RTL (parms), 0)) != STACK_POINTER_REGNUM #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM @@ -3202,44 +2865,73 @@ dbxout_parms (tree parms) The debugger will know from the type that it was actually passed by invisible reference. */ - code = DBX_REGPARM_STABS_CODE; - - /* GDB likes this marked with a special letter. */ - letter = (use_gnu_debug_info_extensions - ? 'a' : DBX_REGPARM_STABS_LETTER); - eff_type = TREE_TYPE (parms); + char regparm_letter; + /* Parm passed in registers and lives in registers or nowhere. */ + + current_sym_code = DBX_REGPARM_STABS_CODE; + if (use_gnu_debug_info_extensions) + regparm_letter = GDB_INV_REF_REGPARM_STABS_LETTER; + else + regparm_letter = DBX_REGPARM_STABS_LETTER; /* DECL_RTL looks like (MEM (REG...). Get the register number. If it is an unallocated pseudo-reg, then use the register where - it was passed instead. - ??? Why is DBX_REGISTER_NUMBER not used here? */ - + it was passed instead. */ if (REGNO (XEXP (DECL_RTL (parms), 0)) < FIRST_PSEUDO_REGISTER) - number = REGNO (XEXP (DECL_RTL (parms), 0)); + current_sym_value = REGNO (XEXP (DECL_RTL (parms), 0)); + else + current_sym_value = REGNO (DECL_INCOMING_RTL (parms)); + + current_sym_addr = 0; + + FORCE_TEXT; + if (DECL_NAME (parms)) + { + current_sym_nchars + = 2 + strlen (IDENTIFIER_POINTER (DECL_NAME (parms))); + + fprintf (asmfile, "%s\"%s:%c", ASM_STABS_OP, + IDENTIFIER_POINTER (DECL_NAME (parms)), + regparm_letter); + } else - number = REGNO (DECL_INCOMING_RTL (parms)); + { + current_sym_nchars = 8; + fprintf (asmfile, "%s\"(anon):%c", ASM_STABS_OP, + regparm_letter); + } + + dbxout_type (TREE_TYPE (parms), 0); + dbxout_finish_symbol (parms); } - else if (MEM_P (DECL_RTL (parms)) - && MEM_P (XEXP (DECL_RTL (parms), 0))) + else if (GET_CODE (DECL_RTL (parms)) == MEM + && GET_CODE (XEXP (DECL_RTL (parms), 0)) == MEM) { /* Parm was passed via invisible reference, with the reference living on the stack. DECL_RTL looks like (MEM (MEM (PLUS (REG ...) (CONST_INT ...)))) or it could look like (MEM (MEM (REG))). */ - - code = N_PSYM; - letter = 'v'; - eff_type = TREE_TYPE (parms); - - if (!REG_P (XEXP (XEXP (DECL_RTL (parms), 0), 0))) - number = INTVAL (XEXP (XEXP (XEXP (DECL_RTL (parms), 0), 0), 1)); + const char *const decl_name = (DECL_NAME (parms) + ? IDENTIFIER_POINTER (DECL_NAME (parms)) + : "(anon)"); + if (GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 0)) == REG) + current_sym_value = 0; else - number = 0; - - number = DEBUGGER_ARG_OFFSET (number, - XEXP (XEXP (DECL_RTL (parms), 0), 0)); + current_sym_value + = INTVAL (XEXP (XEXP (XEXP (DECL_RTL (parms), 0), 0), 1)); + current_sym_addr = 0; + current_sym_code = N_PSYM; + + FORCE_TEXT; + fprintf (asmfile, "%s\"%s:v", ASM_STABS_OP, decl_name); + + current_sym_value + = DEBUGGER_ARG_OFFSET (current_sym_value, + XEXP (XEXP (DECL_RTL (parms), 0), 0)); + dbxout_type (TREE_TYPE (parms), 0); + dbxout_finish_symbol (parms); } - else if (MEM_P (DECL_RTL (parms)) + else if (GET_CODE (DECL_RTL (parms)) == MEM && XEXP (DECL_RTL (parms), 0) != const0_rtx /* ??? A constant address for a parm can happen when the reg it lives in is equiv to a constant in memory. @@ -3248,43 +2940,53 @@ dbxout_parms (tree parms) { /* Parm was passed in registers but lives on the stack. */ - code = N_PSYM; - letter = 'p'; - eff_type = TREE_TYPE (parms); - + current_sym_code = N_PSYM; /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))), in which case we want the value of that CONST_INT, or (MEM (REG ...)), in which case we use a value of zero. */ - if (!REG_P (XEXP (DECL_RTL (parms), 0))) - number = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)); + if (GET_CODE (XEXP (DECL_RTL (parms), 0)) == REG) + current_sym_value = 0; else - number = 0; + current_sym_value + = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)); + + current_sym_addr = 0; /* Make a big endian correction if the mode of the type of the parameter is not the same as the mode of the rtl. */ if (BYTES_BIG_ENDIAN && TYPE_MODE (TREE_TYPE (parms)) != GET_MODE (DECL_RTL (parms)) && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (parms))) < UNITS_PER_WORD) - number += (GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))) - - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (parms)))); - } - else - /* ??? We don't know how to represent this argument. */ - continue; + { + current_sym_value += + GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))) + - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (parms))); + } - dbxout_begin_complex_stabs (); - - if (DECL_NAME (parms)) - { - stabstr_I (DECL_NAME (parms)); - stabstr_C (':'); + FORCE_TEXT; + if (DECL_NAME (parms)) + { + current_sym_nchars + = 2 + strlen (IDENTIFIER_POINTER (DECL_NAME (parms))); + + fprintf (asmfile, "%s\"%s:%c", ASM_STABS_OP, + IDENTIFIER_POINTER (DECL_NAME (parms)), + DBX_MEMPARM_STABS_LETTER); + } + else + { + current_sym_nchars = 8; + fprintf (asmfile, "%s\"(anon):%c", ASM_STABS_OP, + DBX_MEMPARM_STABS_LETTER); + } + + current_sym_value + = DEBUGGER_ARG_OFFSET (current_sym_value, + XEXP (DECL_RTL (parms), 0)); + dbxout_type (TREE_TYPE (parms), 0); + dbxout_finish_symbol (parms); } - else - stabstr_S ("(anon):"); - stabstr_C (letter); - dbxout_type (eff_type, 0); - dbxout_finish_complex_stabs (parms, code, 0, 0, number); } DBXOUT_DECR_NESTING; } @@ -3308,9 +3010,11 @@ dbxout_reg_parms (tree parms) for (; parms; parms = TREE_CHAIN (parms)) if (DECL_NAME (parms) && PARM_PASSED_IN_MEMORY (parms)) { + dbxout_prepare_symbol (parms); + /* Report parms that live in registers during the function but were passed in memory. */ - if (REG_P (DECL_RTL (parms)) + if (GET_CODE (DECL_RTL (parms)) == REG && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) dbxout_symbol_location (parms, TREE_TYPE (parms), 0, DECL_RTL (parms)); @@ -3318,7 +3022,7 @@ dbxout_reg_parms (tree parms) dbxout_symbol_location (parms, TREE_TYPE (parms), 0, DECL_RTL (parms)); /* Report parms that live in memory but not where they were passed. */ - else if (MEM_P (DECL_RTL (parms)) + else if (GET_CODE (DECL_RTL (parms)) == MEM && ! rtx_equal_p (DECL_RTL (parms), DECL_INCOMING_RTL (parms))) dbxout_symbol_location (parms, TREE_TYPE (parms), 0, DECL_RTL (parms)); @@ -3334,8 +3038,9 @@ dbxout_args (tree args) { while (args) { - stabstr_C (','); + putc (',', asmfile); dbxout_type (TREE_VALUE (args), 0); + CHARS (1); args = TREE_CHAIN (args); } } @@ -3347,11 +3052,17 @@ static void dbx_output_lbrac (const char *label, const char *begin_label ATTRIBUTE_UNUSED) { - dbxout_begin_stabn (N_LBRAC); - if (DBX_BLOCKS_FUNCTION_RELATIVE) - dbxout_stab_value_label_diff (label, begin_label); - else - dbxout_stab_value_label (label); +#ifdef DBX_OUTPUT_LBRAC + DBX_OUTPUT_LBRAC (asmfile, label); +#else + fprintf (asmfile, "%s%d,0,0,", ASM_STABN_OP, N_LBRAC); + assemble_name (asmfile, label); +#if DBX_BLOCKS_FUNCTION_RELATIVE + putc ('-', asmfile); + assemble_name (asmfile, begin_label); +#endif + fprintf (asmfile, "\n"); +#endif } /* Subroutine of dbxout_block. Emit an N_RBRAC stab referencing LABEL. @@ -3361,11 +3072,17 @@ static void dbx_output_rbrac (const char *label, const char *begin_label ATTRIBUTE_UNUSED) { - dbxout_begin_stabn (N_RBRAC); - if (DBX_BLOCKS_FUNCTION_RELATIVE) - dbxout_stab_value_label_diff (label, begin_label); - else - dbxout_stab_value_label (label); +#ifdef DBX_OUTPUT_RBRAC + DBX_OUTPUT_RBRAC (asmfile, label); +#else + fprintf (asmfile, "%s%d,0,0,", ASM_STABN_OP, N_RBRAC); + assemble_name (asmfile, label); +#if DBX_BLOCKS_FUNCTION_RELATIVE + putc ('-', asmfile); + assemble_name (asmfile, begin_label); +#endif + fprintf (asmfile, "\n"); +#endif } /* Output everything about a symbol block (a BLOCK node @@ -3388,9 +3105,11 @@ dbx_output_rbrac (const char *label, static void dbxout_block (tree block, int depth, tree args) { - char begin_label[20]; - /* Reference current function start using LFBB. */ - ASM_GENERATE_INTERNAL_LABEL (begin_label, "LFBB", scope_labelno); + const char *begin_label; + if (current_function_func_begin_label != NULL_TREE) + begin_label = IDENTIFIER_POINTER (current_function_func_begin_label); + else + begin_label = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); while (block) { @@ -3419,7 +3138,7 @@ dbxout_block (tree block, int depth, tree args) if (depth == 0) /* The outermost block doesn't get LBB labels; use - the LFBB local symbol emitted by dbxout_begin_prologue. */ + the function symbol. */ scope_start = begin_label; else { @@ -3433,11 +3152,10 @@ dbxout_block (tree block, int depth, tree args) tree decl = BLOCK_VARS (block); while (decl) { - dbxout_begin_complex_stabs (); - stabstr_I (DECL_NAME (decl)); - stabstr_S (":C1"); - dbxout_finish_complex_stabs (0, N_CATCH, 0, - scope_start, 0); + fprintf (asmfile, "%s\"%s:C1\",%d,0,0,", ASM_STABS_OP, + IDENTIFIER_POINTER (DECL_NAME (decl)), N_CATCH); + assemble_name (asmfile, scope_start); + fprintf (asmfile, "\n"); decl = TREE_CHAIN (decl); } } @@ -3474,12 +3192,7 @@ dbxout_block (tree block, int depth, tree args) static void dbxout_begin_function (tree decl) { - int saved_tree_used1; - - if (DECL_IGNORED_P (decl)) - return; - - saved_tree_used1 = TREE_USED (decl); + int saved_tree_used1 = TREE_USED (decl); TREE_USED (decl) = 1; if (DECL_NAME (DECL_RESULT (decl)) != 0) { diff --git a/contrib/gcc/dwarfout.c b/contrib/gcc/dwarfout.c new file mode 100644 index 0000000..bbbfcfc --- /dev/null +++ b/contrib/gcc/dwarfout.c @@ -0,0 +1,6561 @@ +/* Output Dwarf format symbol table information from the GNU C compiler. + Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 2002, + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Ron Guilmette (rfg@monkeys.com) of Network Computing Devices. + +This file is part of GCC. + +GCC 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. + +GCC 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 GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* + + Notes on the GNU Implementation of DWARF Debugging Information + -------------------------------------------------------------- + Last Major Update: Sun Jul 17 08:17:42 PDT 1994 by rfg@segfault.us.com + ------------------------------------------------------------ + + This file describes special and unique aspects of the GNU implementation of + the DWARF Version 1 debugging information language, as provided in the GNU + version 2.x compiler(s). + + For general information about the DWARF debugging information language, + you should obtain the DWARF version 1.1 specification document (and perhaps + also the DWARF version 2 draft specification document) developed by the + (now defunct) UNIX International Programming Languages Special Interest Group. + + To obtain a copy of the DWARF Version 1 and/or DWARF Version 2 + specification, visit the web page for the DWARF Version 2 committee, at + + http://www.eagercon.com/dwarf/dwarf2std.htm + + The generation of DWARF debugging information by the GNU version 2.x C + compiler has now been tested rather extensively for m88k, i386, i860, and + SPARC targets. The DWARF output of the GNU C compiler appears to inter- + operate well with the standard SVR4 SDB debugger on these kinds of target + systems (but of course, there are no guarantees). + + DWARF 1 generation for the GNU g++ compiler is implemented, but limited. + C++ users should definitely use DWARF 2 instead. + + Future plans for the dwarfout.c module of the GNU compiler(s) includes the + addition of full support for GNU FORTRAN. (This should, in theory, be a + lot simpler to add than adding support for g++... but we'll see.) + + Many features of the DWARF version 2 specification have been adapted to + (and used in) the GNU implementation of DWARF (version 1). In most of + these cases, a DWARF version 2 approach is used in place of (or in addition + to) DWARF version 1 stuff simply because it is apparent that DWARF version + 1 is not sufficiently expressive to provide the kinds of information which + may be necessary to support really robust debugging. In all of these cases + however, the use of DWARF version 2 features should not interfere in any + way with the interoperability (of GNU compilers) with generally available + "classic" (pre version 1) DWARF consumer tools (e.g. SVR4 SDB). + + The DWARF generation enhancement for the GNU compiler(s) was initially + donated to the Free Software Foundation by Network Computing Devices. + (Thanks NCD!) Additional development and maintenance of dwarfout.c has + been largely supported (i.e. funded) by Intel Corporation. (Thanks Intel!) + + If you have questions or comments about the DWARF generation feature, please + send mail to me <rfg@netcom.com>. I will be happy to investigate any bugs + reported and I may even provide fixes (but of course, I can make no promises). + + The DWARF debugging information produced by GCC may deviate in a few minor + (but perhaps significant) respects from the DWARF debugging information + currently produced by other C compilers. A serious attempt has been made + however to conform to the published specifications, to existing practice, + and to generally accepted norms in the GNU implementation of DWARF. + + ** IMPORTANT NOTE ** ** IMPORTANT NOTE ** ** IMPORTANT NOTE ** + + Under normal circumstances, the DWARF information generated by the GNU + compilers (in an assembly language file) is essentially impossible for + a human being to read. This fact can make it very difficult to debug + certain DWARF-related problems. In order to overcome this difficulty, + a feature has been added to dwarfout.c (enabled by the -dA + option) which causes additional comments to be placed into the assembly + language output file, out to the right-hand side of most bits of DWARF + material. The comments indicate (far more clearly that the obscure + DWARF hex codes do) what is actually being encoded in DWARF. Thus, the + -dA option can be highly useful for those who must study the + DWARF output from the GNU compilers in detail. + + --------- + + (Footnote: Within this file, the term `Debugging Information Entry' will + be abbreviated as `DIE'.) + + + Release Notes (aka known bugs) + ------------------------------- + + In one very obscure case involving dynamically sized arrays, the DWARF + "location information" for such an array may make it appear that the + array has been totally optimized out of existence, when in fact it + *must* actually exist. (This only happens when you are using *both* -g + *and* -O.) This is due to aggressive dead store elimination in the + compiler, and to the fact that the DECL_RTL expressions associated with + variables are not always updated to correctly reflect the effects of + GCC's aggressive dead store elimination. + + ------------------------------- + + When attempting to set a breakpoint at the "start" of a function compiled + with -g1, the debugger currently has no way of knowing exactly where the + end of the prologue code for the function is. Thus, for most targets, + all the debugger can do is to set the breakpoint at the AT_low_pc address + for the function. But if you stop there and then try to look at one or + more of the formal parameter values, they may not have been "homed" yet, + so you may get inaccurate answers (or perhaps even addressing errors). + + Some people may consider this simply a non-feature, but I consider it a + bug, and I hope to provide some GNU-specific attributes (on function + DIEs) which will specify the address of the end of the prologue and the + address of the beginning of the epilogue in a future release. + + ------------------------------- + + It is believed at this time that old bugs relating to the AT_bit_offset + values for bit-fields have been fixed. + + There may still be some very obscure bugs relating to the DWARF description + of type `long long' bit-fields for target machines (e.g. 80x86 machines) + where the alignment of type `long long' data objects is different from + (and less than) the size of a type `long long' data object. + + Please report any problems with the DWARF description of bit-fields as you + would any other GCC bug. (Procedures for bug reporting are given in the + GNU C compiler manual.) + + -------------------------------- + + At this time, GCC does not know how to handle the GNU C "nested functions" + extension. (See the GCC manual for more info on this extension to ANSI C.) + + -------------------------------- + + The GNU compilers now represent inline functions (and inlined instances + thereof) in exactly the manner described by the current DWARF version 2 + (draft) specification. The version 1 specification for handling inline + functions (and inlined instances) was known to be brain-damaged (by the + PLSIG) when the version 1 spec was finalized, but it was simply too late + in the cycle to get it removed before the version 1 spec was formally + released to the public (by UI). + + -------------------------------- + + At this time, GCC does not generate the kind of really precise information + about the exact declared types of entities with signed integral types which + is required by the current DWARF draft specification. + + Specifically, the current DWARF draft specification seems to require that + the type of a non-unsigned integral bit-field member of a struct or union + type be represented as either a "signed" type or as a "plain" type, + depending upon the exact set of keywords that were used in the + type specification for the given bit-field member. It was felt (by the + UI/PLSIG) that this distinction between "plain" and "signed" integral types + could have some significance (in the case of bit-fields) because ANSI C + does not constrain the signedness of a plain bit-field, whereas it does + constrain the signedness of an explicitly "signed" bit-field. For this + reason, the current DWARF specification calls for compilers to produce + type information (for *all* integral typed entities... not just bit-fields) + which explicitly indicates the signedness of the relevant type to be + "signed" or "plain" or "unsigned". + + Unfortunately, the GNU DWARF implementation is currently incapable of making + such distinctions. + + -------------------------------- + + + Known Interoperability Problems + ------------------------------- + + Although the GNU implementation of DWARF conforms (for the most part) with + the current UI/PLSIG DWARF version 1 specification (with many compatible + version 2 features added in as "vendor specific extensions" just for good + measure) there are a few known cases where GCC's DWARF output can cause + some confusion for "classic" (pre version 1) DWARF consumers such as the + System V Release 4 SDB debugger. These cases are described in this section. + + -------------------------------- + + The DWARF version 1 specification includes the fundamental type codes + FT_ext_prec_float, FT_complex, FT_dbl_prec_complex, and FT_ext_prec_complex. + Since GNU C is only a C compiler (and since C doesn't provide any "complex" + data types) the only one of these fundamental type codes which GCC ever + generates is FT_ext_prec_float. This fundamental type code is generated + by GCC for the `long double' data type. Unfortunately, due to an apparent + bug in the SVR4 SDB debugger, SDB can become very confused wherever any + attempt is made to print a variable, parameter, or field whose type was + given in terms of FT_ext_prec_float. + + (Actually, SVR4 SDB fails to understand *any* of the four fundamental type + codes mentioned here. This will fact will cause additional problems when + there is a GNU FORTRAN front-end.) + + -------------------------------- + + In general, it appears that SVR4 SDB is not able to effectively ignore + fundamental type codes in the "implementation defined" range. This can + cause problems when a program being debugged uses the `long long' data + type (or the signed or unsigned varieties thereof) because these types + are not defined by ANSI C, and thus, GCC must use its own private fundamental + type codes (from the implementation-defined range) to represent these types. + + -------------------------------- + + + General GNU DWARF extensions + ---------------------------- + + In the current DWARF version 1 specification, no mechanism is specified by + which accurate information about executable code from include files can be + properly (and fully) described. (The DWARF version 2 specification *does* + specify such a mechanism, but it is about 10 times more complicated than + it needs to be so I'm not terribly anxious to try to implement it right + away.) + + In the GNU implementation of DWARF version 1, a fully downward-compatible + extension has been implemented which permits the GNU compilers to specify + which executable lines come from which files. This extension places + additional information (about source file names) in GNU-specific sections + (which should be totally ignored by all non-GNU DWARF consumers) so that + this extended information can be provided (to GNU DWARF consumers) in a way + which is totally transparent (and invisible) to non-GNU DWARF consumers + (e.g. the SVR4 SDB debugger). The additional information is placed *only* + in specialized GNU-specific sections, where it should never even be seen + by non-GNU DWARF consumers. + + To understand this GNU DWARF extension, imagine that the sequence of entries + in the .lines section is broken up into several subsections. Each contiguous + sequence of .line entries which relates to a sequence of lines (or statements) + from one particular file (either a `base' file or an `include' file) could + be called a `line entries chunk' (LEC). + + For each LEC there is one entry in the .debug_srcinfo section. + + Each normal entry in the .debug_srcinfo section consists of two 4-byte + words of data as follows: + + (1) The starting address (relative to the entire .line section) + of the first .line entry in the relevant LEC. + + (2) The starting address (relative to the entire .debug_sfnames + section) of a NUL terminated string representing the + relevant filename. (This filename name be either a + relative or an absolute filename, depending upon how the + given source file was located during compilation.) + + Obviously, each .debug_srcinfo entry allows you to find the relevant filename, + and it also points you to the first .line entry that was generated as a result + of having compiled a given source line from the given source file. + + Each subsequent .line entry should also be assumed to have been produced + as a result of compiling yet more lines from the same file. The end of + any given LEC is easily found by looking at the first 4-byte pointer in + the *next* .debug_srcinfo entry. That next .debug_srcinfo entry points + to a new and different LEC, so the preceding LEC (implicitly) must have + ended with the last .line section entry which occurs at the 2 1/2 words + just before the address given in the first pointer of the new .debug_srcinfo + entry. + + The following picture may help to clarify this feature. Let's assume that + `LE' stands for `.line entry'. Also, assume that `* 'stands for a pointer. + + + .line section .debug_srcinfo section .debug_sfnames section + ---------------------------------------------------------------- + + LE <---------------------- * + LE * -----------------> "foobar.c" <--- + LE | + LE | + LE <---------------------- * | + LE * -----------------> "foobar.h" <| | + LE | | + LE | | + LE <---------------------- * | | + LE * -----------------> "inner.h" | | + LE | | + LE <---------------------- * | | + LE * ------------------------------- | + LE | + LE | + LE | + LE | + LE <---------------------- * | + LE * ----------------------------------- + LE + LE + LE + + In effect, each entry in the .debug_srcinfo section points to *both* a + filename (in the .debug_sfnames section) and to the start of a block of + consecutive LEs (in the .line section). + + Note that just like in the .line section, there are specialized first and + last entries in the .debug_srcinfo section for each object file. These + special first and last entries for the .debug_srcinfo section are very + different from the normal .debug_srcinfo section entries. They provide + additional information which may be helpful to a debugger when it is + interpreting the data in the .debug_srcinfo, .debug_sfnames, and .line + sections. + + The first entry in the .debug_srcinfo section for each compilation unit + consists of five 4-byte words of data. The contents of these five words + should be interpreted (by debuggers) as follows: + + (1) The starting address (relative to the entire .line section) + of the .line section for this compilation unit. + + (2) The starting address (relative to the entire .debug_sfnames + section) of the .debug_sfnames section for this compilation + unit. + + (3) The starting address (in the execution virtual address space) + of the .text section for this compilation unit. + + (4) The ending address plus one (in the execution virtual address + space) of the .text section for this compilation unit. + + (5) The date/time (in seconds since midnight 1/1/70) at which the + compilation of this compilation unit occurred. This value + should be interpreted as an unsigned quantity because gcc + might be configured to generate a default value of 0xffffffff + in this field (in cases where it is desired to have object + files created at different times from identical source files + be byte-for-byte identical). By default, these timestamps + are *not* generated by dwarfout.c (so that object files + compiled at different times will be byte-for-byte identical). + If you wish to enable this "timestamp" feature however, you + can simply place a #define for the symbol `DWARF_TIMESTAMPS' + in your target configuration file and then rebuild the GNU + compiler(s). + + Note that the first string placed into the .debug_sfnames section for each + compilation unit is the name of the directory in which compilation occurred. + This string ends with a `/' (to help indicate that it is the pathname of a + directory). Thus, the second word of each specialized initial .debug_srcinfo + entry for each compilation unit may be used as a pointer to the (string) + name of the compilation directory, and that string may in turn be used to + "absolutize" any relative pathnames which may appear later on in the + .debug_sfnames section entries for the same compilation unit. + + The fifth and last word of each specialized starting entry for a compilation + unit in the .debug_srcinfo section may (depending upon your configuration) + indicate the date/time of compilation, and this may be used (by a debugger) + to determine if any of the source files which contributed code to this + compilation unit are newer than the object code for the compilation unit + itself. If so, the debugger may wish to print an "out-of-date" warning + about the compilation unit. + + The .debug_srcinfo section associated with each compilation will also have + a specialized terminating entry. This terminating .debug_srcinfo section + entry will consist of the following two 4-byte words of data: + + (1) The offset, measured from the start of the .line section to + the beginning of the terminating entry for the .line section. + + (2) A word containing the value 0xffffffff. + + -------------------------------- + + In the current DWARF version 1 specification, no mechanism is specified by + which information about macro definitions and un-definitions may be provided + to the DWARF consumer. + + The DWARF version 2 (draft) specification does specify such a mechanism. + That specification was based on the GNU ("vendor specific extension") + which provided some support for macro definitions and un-definitions, + but the "official" DWARF version 2 (draft) specification mechanism for + handling macros and the GNU implementation have diverged somewhat. I + plan to update the GNU implementation to conform to the "official" + DWARF version 2 (draft) specification as soon as I get time to do that. + + Note that in the GNU implementation, additional information about macro + definitions and un-definitions is *only* provided when the -g3 level of + debug-info production is selected. (The default level is -g2 and the + plain old -g option is considered to be identical to -g2.) + + GCC records information about macro definitions and undefinitions primarily + in a section called the .debug_macinfo section. Normal entries in the + .debug_macinfo section consist of the following three parts: + + (1) A special "type" byte. + + (2) A 3-byte line-number/filename-offset field. + + (3) A NUL terminated string. + + The interpretation of the second and third parts is dependent upon the + value of the leading (type) byte. + + The type byte may have one of four values depending upon the type of the + .debug_macinfo entry which follows. The 1-byte MACINFO type codes presently + used, and their meanings are as follows: + + MACINFO_start A base file or an include file starts here. + MACINFO_resume The current base or include file ends here. + MACINFO_define A #define directive occurs here. + MACINFO_undef A #undef directive occur here. + + (Note that the MACINFO_... codes mentioned here are simply symbolic names + for constants which are defined in the GNU dwarf.h file.) + + For MACINFO_define and MACINFO_undef entries, the second (3-byte) field + contains the number of the source line (relative to the start of the current + base source file or the current include files) when the #define or #undef + directive appears. For a MACINFO_define entry, the following string field + contains the name of the macro which is defined, followed by its definition. + Note that the definition is always separated from the name of the macro + by at least one whitespace character. For a MACINFO_undef entry, the + string which follows the 3-byte line number field contains just the name + of the macro which is being undef'ed. + + For a MACINFO_start entry, the 3-byte field following the type byte contains + the offset, relative to the start of the .debug_sfnames section for the + current compilation unit, of a string which names the new source file which + is beginning its inclusion at this point. Following that 3-byte field, + each MACINFO_start entry always contains a zero length NUL terminated + string. + + For a MACINFO_resume entry, the 3-byte field following the type byte contains + the line number WITHIN THE INCLUDING FILE at which the inclusion of the + current file (whose inclusion ends here) was initiated. Following that + 3-byte field, each MACINFO_resume entry always contains a zero length NUL + terminated string. + + Each set of .debug_macinfo entries for each compilation unit is terminated + by a special .debug_macinfo entry consisting of a 4-byte zero value followed + by a single NUL byte. + + -------------------------------- + + In the current DWARF draft specification, no provision is made for providing + a separate level of (limited) debugging information necessary to support + tracebacks (only) through fully-debugged code (e.g. code in system libraries). + + A proposal to define such a level was submitted (by me) to the UI/PLSIG. + This proposal was rejected by the UI/PLSIG for inclusion into the DWARF + version 1 specification for two reasons. First, it was felt (by the PLSIG) + that the issues involved in supporting a "traceback only" subset of DWARF + were not well understood. Second, and perhaps more importantly, the PLSIG + is already having enough trouble agreeing on what it means to be "conforming" + to the DWARF specification, and it was felt that trying to specify multiple + different *levels* of conformance would only complicate our discussions of + this already divisive issue. Nonetheless, the GNU implementation of DWARF + provides an abbreviated "traceback only" level of debug-info production for + use with fully-debugged "system library" code. This level should only be + used for fully debugged system library code, and even then, it should only + be used where there is a very strong need to conserve disk space. This + abbreviated level of debug-info production can be used by specifying the + -g1 option on the compilation command line. + + -------------------------------- + + As mentioned above, the GNU implementation of DWARF currently uses the DWARF + version 2 (draft) approach for inline functions (and inlined instances + thereof). This is used in preference to the version 1 approach because + (quite simply) the version 1 approach is highly brain-damaged and probably + unworkable. + + -------------------------------- + + + GNU DWARF Representation of GNU C Extensions to ANSI C + ------------------------------------------------------ + + The file dwarfout.c has been designed and implemented so as to provide + some reasonable DWARF representation for each and every declarative + construct which is accepted by the GNU C compiler. Since the GNU C + compiler accepts a superset of ANSI C, this means that there are some + cases in which the DWARF information produced by GCC must take some + liberties in improvising DWARF representations for declarations which + are only valid in (extended) GNU C. + + In particular, GNU C provides at least three significant extensions to + ANSI C when it comes to declarations. These are (1) inline functions, + and (2) dynamic arrays, and (3) incomplete enum types. (See the GCC + manual for more information on these GNU extensions to ANSI C.) When + used, these GNU C extensions are represented (in the generated DWARF + output of GCC) in the most natural and intuitively obvious ways. + + In the case of inline functions, the DWARF representation is exactly as + called for in the DWARF version 2 (draft) specification for an identical + function written in C++; i.e. we "reuse" the representation of inline + functions which has been defined for C++ to support this GNU C extension. + + In the case of dynamic arrays, we use the most obvious representational + mechanism available; i.e. an array type in which the upper bound of + some dimension (usually the first and only dimension) is a variable + rather than a constant. (See the DWARF version 1 specification for more + details.) + + In the case of incomplete enum types, such types are represented simply + as TAG_enumeration_type DIEs which DO NOT contain either AT_byte_size + attributes or AT_element_list attributes. + + -------------------------------- + + + Future Directions + ----------------- + + The codes, formats, and other paraphernalia necessary to provide proper + support for symbolic debugging for the C++ language are still being worked + on by the UI/PLSIG. The vast majority of the additions to DWARF which will + be needed to completely support C++ have already been hashed out and agreed + upon, but a few small issues (e.g. anonymous unions, access declarations) + are still being discussed. Also, we in the PLSIG are still discussing + whether or not we need to do anything special for C++ templates. (At this + time it is not yet clear whether we even need to do anything special for + these.) + + With regard to FORTRAN, the UI/PLSIG has defined what is believed to be a + complete and sufficient set of codes and rules for adequately representing + all of FORTRAN 77, and most of Fortran 90 in DWARF. While some support for + this has been implemented in dwarfout.c, further implementation and testing + is needed. + + GNU DWARF support for other languages (i.e. Pascal and Modula) is a moot + issue until there are GNU front-ends for these other languages. + + As currently defined, DWARF only describes a (binary) language which can + be used to communicate symbolic debugging information from a compiler + through an assembler and a linker, to a debugger. There is no clear + specification of what processing should be (or must be) done by the + assembler and/or the linker. Fortunately, the role of the assembler + is easily inferred (by anyone knowledgeable about assemblers) just by + looking at examples of assembly-level DWARF code. Sadly though, the + allowable (or required) processing steps performed by a linker are + harder to infer and (perhaps) even harder to agree upon. There are + several forms of very useful `post-processing' steps which intelligent + linkers *could* (in theory) perform on object files containing DWARF, + but any and all such link-time transformations are currently both disallowed + and unspecified. + + In particular, possible link-time transformations of DWARF code which could + provide significant benefits include (but are not limited to): + + Commonization of duplicate DIEs obtained from multiple input + (object) files. + + Cross-compilation type checking based upon DWARF type information + for objects and functions. + + Other possible `compacting' transformations designed to save disk + space and to reduce linker & debugger I/O activity. + +*/ + +#include "config.h" + +#ifdef DWARF_DEBUGGING_INFO +#include "system.h" +#include "dwarf.h" +#include "tree.h" +#include "flags.h" +#include "function.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "insn-config.h" +#include "reload.h" +#include "output.h" +#include "dwarf2asm.h" +#include "toplev.h" +#include "tm_p.h" +#include "debug.h" +#include "langhooks.h" + +/* NOTE: In the comments in this file, many references are made to + so called "Debugging Information Entries". For the sake of brevity, + this term is abbreviated to `DIE' throughout the remainder of this + file. */ + +/* Note that the implementation of C++ support herein is (as yet) unfinished. + If you want to try to complete it, more power to you. */ + +/* How to start an assembler comment. */ +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START ";#" +#endif + +/* How to print out a register name. */ +#ifndef PRINT_REG +#define PRINT_REG(RTX, CODE, FILE) \ + fprintf ((FILE), "%s", reg_names[REGNO (RTX)]) +#endif + +/* Define a macro which returns nonzero for any tagged type which is + used (directly or indirectly) in the specification of either some + function's return type or some formal parameter of some function. + We use this macro when we are operating in "terse" mode to help us + know what tagged types have to be represented in Dwarf (even in + terse mode) and which ones don't. + + A flag bit with this meaning really should be a part of the normal + GCC ..._TYPE nodes, but at the moment, there is no such bit defined + for these nodes. For now, we have to just fake it. It it safe for + us to simply return zero for all complete tagged types (which will + get forced out anyway if they were used in the specification of some + formal or return type) and nonzero for all incomplete tagged types. +*/ + +#define TYPE_USED_FOR_FUNCTION(tagged_type) (TYPE_SIZE (tagged_type) == 0) + +/* Define a macro which returns nonzero for a TYPE_DECL which was + implicitly generated for a tagged type. + + Note that unlike the gcc front end (which generates a NULL named + TYPE_DECL node for each complete tagged type, each array type, and + each function type node created) the g++ front end generates a + _named_ TYPE_DECL node for each tagged type node created. + These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to + generate a DW_TAG_typedef DIE for them. */ +#define TYPE_DECL_IS_STUB(decl) \ + (DECL_NAME (decl) == NULL \ + || (DECL_ARTIFICIAL (decl) \ + && is_tagged_type (TREE_TYPE (decl)) \ + && decl == TYPE_STUB_DECL (TREE_TYPE (decl)))) + +/* Maximum size (in bytes) of an artificially generated label. */ + +#define MAX_ARTIFICIAL_LABEL_BYTES 30 + +/* Structure to keep track of source filenames. */ + +struct filename_entry { + unsigned number; + const char * name; +}; + +typedef struct filename_entry filename_entry; + +/* Pointer to an array of elements, each one having the structure above. */ + +static filename_entry *filename_table; + +/* Total number of entries in the table (i.e. array) pointed to by + `filename_table'. This is the *total* and includes both used and + unused slots. */ + +static unsigned ft_entries_allocated; + +/* Number of entries in the filename_table which are actually in use. */ + +static unsigned ft_entries; + +/* Size (in elements) of increments by which we may expand the filename + table. Actually, a single hunk of space of this size should be enough + for most typical programs. */ + +#define FT_ENTRIES_INCREMENT 64 + +/* Local pointer to the name of the main input file. Initialized in + dwarfout_init. */ + +static const char *primary_filename; + +/* Counter to generate unique names for DIEs. */ + +static unsigned next_unused_dienum = 1; + +/* Number of the DIE which is currently being generated. */ + +static unsigned current_dienum; + +/* Number to use for the special "pubname" label on the next DIE which + represents a function or data object defined in this compilation + unit which has "extern" linkage. */ + +static int next_pubname_number = 0; + +#define NEXT_DIE_NUM pending_sibling_stack[pending_siblings-1] + +/* Pointer to a dynamically allocated list of pre-reserved and still + pending sibling DIE numbers. Note that this list will grow as needed. */ + +static unsigned *pending_sibling_stack; + +/* Counter to keep track of the number of pre-reserved and still pending + sibling DIE numbers. */ + +static unsigned pending_siblings; + +/* The currently allocated size of the above list (expressed in number of + list elements). */ + +static unsigned pending_siblings_allocated; + +/* Size (in elements) of increments by which we may expand the pending + sibling stack. Actually, a single hunk of space of this size should + be enough for most typical programs. */ + +#define PENDING_SIBLINGS_INCREMENT 64 + +/* Nonzero if we are performing our file-scope finalization pass and if + we should force out Dwarf descriptions of any and all file-scope + tagged types which are still incomplete types. */ + +static int finalizing = 0; + +/* A pointer to the base of a list of pending types which we haven't + generated DIEs for yet, but which we will have to come back to + later on. */ + +static tree *pending_types_list; + +/* Number of elements currently allocated for the pending_types_list. */ + +static unsigned pending_types_allocated; + +/* Number of elements of pending_types_list currently in use. */ + +static unsigned pending_types; + +/* Size (in elements) of increments by which we may expand the pending + types list. Actually, a single hunk of space of this size should + be enough for most typical programs. */ + +#define PENDING_TYPES_INCREMENT 64 + +/* A pointer to the base of a list of incomplete types which might be + completed at some later time. */ + +static tree *incomplete_types_list; + +/* Number of elements currently allocated for the incomplete_types_list. */ +static unsigned incomplete_types_allocated; + +/* Number of elements of incomplete_types_list currently in use. */ +static unsigned incomplete_types; + +/* Size (in elements) of increments by which we may expand the incomplete + types list. Actually, a single hunk of space of this size should + be enough for most typical programs. */ +#define INCOMPLETE_TYPES_INCREMENT 64 + +/* Pointer to an artificial RECORD_TYPE which we create in dwarfout_init. + This is used in a hack to help us get the DIEs describing types of + formal parameters to come *after* all of the DIEs describing the formal + parameters themselves. That's necessary in order to be compatible + with what the brain-damaged svr4 SDB debugger requires. */ + +static tree fake_containing_scope; + +/* A pointer to the ..._DECL node which we have most recently been working + on. We keep this around just in case something about it looks screwy + and we want to tell the user what the source coordinates for the actual + declaration are. */ + +static tree dwarf_last_decl; + +/* A flag indicating that we are emitting the member declarations of a + class, so member functions and variables should not be entirely emitted. + This is a kludge to avoid passing a second argument to output_*_die. */ + +static int in_class; + +/* Forward declarations for functions defined in this file. */ + +static void dwarfout_init PARAMS ((const char *)); +static void dwarfout_finish PARAMS ((const char *)); +static void dwarfout_define PARAMS ((unsigned int, const char *)); +static void dwarfout_undef PARAMS ((unsigned int, const char *)); +static void dwarfout_start_source_file PARAMS ((unsigned, const char *)); +static void dwarfout_start_source_file_check PARAMS ((unsigned, const char *)); +static void dwarfout_end_source_file PARAMS ((unsigned)); +static void dwarfout_end_source_file_check PARAMS ((unsigned)); +static void dwarfout_begin_block PARAMS ((unsigned, unsigned)); +static void dwarfout_end_block PARAMS ((unsigned, unsigned)); +static void dwarfout_end_epilogue PARAMS ((unsigned int, const char *)); +static void dwarfout_source_line PARAMS ((unsigned int, const char *)); +static void dwarfout_end_prologue PARAMS ((unsigned int, const char *)); +static void dwarfout_end_function PARAMS ((unsigned int)); +static void dwarfout_function_decl PARAMS ((tree)); +static void dwarfout_global_decl PARAMS ((tree)); +static void dwarfout_deferred_inline_function PARAMS ((tree)); +static void dwarfout_file_scope_decl PARAMS ((tree , int)); +static const char *dwarf_tag_name PARAMS ((unsigned)); +static const char *dwarf_attr_name PARAMS ((unsigned)); +static const char *dwarf_stack_op_name PARAMS ((unsigned)); +static const char *dwarf_typemod_name PARAMS ((unsigned)); +static const char *dwarf_fmt_byte_name PARAMS ((unsigned)); +static const char *dwarf_fund_type_name PARAMS ((unsigned)); +static tree decl_ultimate_origin PARAMS ((tree)); +static tree block_ultimate_origin PARAMS ((tree)); +static tree decl_class_context PARAMS ((tree)); +#if 0 +static void output_unsigned_leb128 PARAMS ((unsigned long)); +static void output_signed_leb128 PARAMS ((long)); +#endif +static int fundamental_type_code PARAMS ((tree)); +static tree root_type_1 PARAMS ((tree, int)); +static tree root_type PARAMS ((tree)); +static void write_modifier_bytes_1 PARAMS ((tree, int, int, int)); +static void write_modifier_bytes PARAMS ((tree, int, int)); +static inline int type_is_fundamental PARAMS ((tree)); +static void equate_decl_number_to_die_number PARAMS ((tree)); +static inline void equate_type_number_to_die_number PARAMS ((tree)); +static void output_reg_number PARAMS ((rtx)); +static void output_mem_loc_descriptor PARAMS ((rtx)); +static void output_loc_descriptor PARAMS ((rtx)); +static void output_bound_representation PARAMS ((tree, unsigned, int)); +static void output_enumeral_list PARAMS ((tree)); +static inline HOST_WIDE_INT ceiling PARAMS ((HOST_WIDE_INT, unsigned int)); +static inline tree field_type PARAMS ((tree)); +static inline unsigned int simple_type_align_in_bits PARAMS ((tree)); +static inline unsigned HOST_WIDE_INT simple_type_size_in_bits PARAMS ((tree)); +static HOST_WIDE_INT field_byte_offset PARAMS ((tree)); +static inline void sibling_attribute PARAMS ((void)); +static void location_attribute PARAMS ((rtx)); +static void data_member_location_attribute PARAMS ((tree)); +static void const_value_attribute PARAMS ((rtx)); +static void location_or_const_value_attribute PARAMS ((tree)); +static inline void name_attribute PARAMS ((const char *)); +static inline void fund_type_attribute PARAMS ((unsigned)); +static void mod_fund_type_attribute PARAMS ((tree, int, int)); +static inline void user_def_type_attribute PARAMS ((tree)); +static void mod_u_d_type_attribute PARAMS ((tree, int, int)); +#ifdef USE_ORDERING_ATTRIBUTE +static inline void ordering_attribute PARAMS ((unsigned)); +#endif /* defined(USE_ORDERING_ATTRIBUTE) */ +static void subscript_data_attribute PARAMS ((tree)); +static void byte_size_attribute PARAMS ((tree)); +static inline void bit_offset_attribute PARAMS ((tree)); +static inline void bit_size_attribute PARAMS ((tree)); +static inline void element_list_attribute PARAMS ((tree)); +static inline void stmt_list_attribute PARAMS ((const char *)); +static inline void low_pc_attribute PARAMS ((const char *)); +static inline void high_pc_attribute PARAMS ((const char *)); +static inline void body_begin_attribute PARAMS ((const char *)); +static inline void body_end_attribute PARAMS ((const char *)); +static inline void language_attribute PARAMS ((unsigned)); +static inline void member_attribute PARAMS ((tree)); +#if 0 +static inline void string_length_attribute PARAMS ((tree)); +#endif +static inline void comp_dir_attribute PARAMS ((const char *)); +static inline void sf_names_attribute PARAMS ((const char *)); +static inline void src_info_attribute PARAMS ((const char *)); +static inline void mac_info_attribute PARAMS ((const char *)); +static inline void prototyped_attribute PARAMS ((tree)); +static inline void producer_attribute PARAMS ((const char *)); +static inline void inline_attribute PARAMS ((tree)); +static inline void containing_type_attribute PARAMS ((tree)); +static inline void abstract_origin_attribute PARAMS ((tree)); +#ifdef DWARF_DECL_COORDINATES +static inline void src_coords_attribute PARAMS ((unsigned, unsigned)); +#endif /* defined(DWARF_DECL_COORDINATES) */ +static inline void pure_or_virtual_attribute PARAMS ((tree)); +static void name_and_src_coords_attributes PARAMS ((tree)); +static void type_attribute PARAMS ((tree, int, int)); +static const char *type_tag PARAMS ((tree)); +static inline void dienum_push PARAMS ((void)); +static inline void dienum_pop PARAMS ((void)); +static inline tree member_declared_type PARAMS ((tree)); +static const char *function_start_label PARAMS ((tree)); +static void output_array_type_die PARAMS ((void *)); +static void output_set_type_die PARAMS ((void *)); +#if 0 +static void output_entry_point_die PARAMS ((void *)); +#endif +static void output_inlined_enumeration_type_die PARAMS ((void *)); +static void output_inlined_structure_type_die PARAMS ((void *)); +static void output_inlined_union_type_die PARAMS ((void *)); +static void output_enumeration_type_die PARAMS ((void *)); +static void output_formal_parameter_die PARAMS ((void *)); +static void output_global_subroutine_die PARAMS ((void *)); +static void output_global_variable_die PARAMS ((void *)); +static void output_label_die PARAMS ((void *)); +static void output_lexical_block_die PARAMS ((void *)); +static void output_inlined_subroutine_die PARAMS ((void *)); +static void output_local_variable_die PARAMS ((void *)); +static void output_member_die PARAMS ((void *)); +#if 0 +static void output_pointer_type_die PARAMS ((void *)); +static void output_reference_type_die PARAMS ((void *)); +#endif +static void output_ptr_to_mbr_type_die PARAMS ((void *)); +static void output_compile_unit_die PARAMS ((void *)); +static void output_string_type_die PARAMS ((void *)); +static void output_inheritance_die PARAMS ((void *)); +static void output_structure_type_die PARAMS ((void *)); +static void output_local_subroutine_die PARAMS ((void *)); +static void output_subroutine_type_die PARAMS ((void *)); +static void output_typedef_die PARAMS ((void *)); +static void output_union_type_die PARAMS ((void *)); +static void output_unspecified_parameters_die PARAMS ((void *)); +static void output_padded_null_die PARAMS ((void *)); +static void output_die PARAMS ((void (*)(void *), void *)); +static void end_sibling_chain PARAMS ((void)); +static void output_formal_types PARAMS ((tree)); +static void pend_type PARAMS ((tree)); +static int type_ok_for_scope PARAMS ((tree, tree)); +static void output_pending_types_for_scope PARAMS ((tree)); +static void output_type PARAMS ((tree, tree)); +static void output_tagged_type_instantiation PARAMS ((tree)); +static void output_block PARAMS ((tree, int)); +static void output_decls_for_scope PARAMS ((tree, int)); +static void output_decl PARAMS ((tree, tree)); +static void shuffle_filename_entry PARAMS ((filename_entry *)); +static void generate_new_sfname_entry PARAMS ((void)); +static unsigned lookup_filename PARAMS ((const char *)); +static void generate_srcinfo_entry PARAMS ((unsigned, unsigned)); +static void generate_macinfo_entry PARAMS ((unsigned int, rtx, + const char *)); +static int is_pseudo_reg PARAMS ((rtx)); +static tree type_main_variant PARAMS ((tree)); +static int is_tagged_type PARAMS ((tree)); +static int is_redundant_typedef PARAMS ((tree)); +static void add_incomplete_type PARAMS ((tree)); +static void retry_incomplete_types PARAMS ((void)); + +/* Definitions of defaults for assembler-dependent names of various + pseudo-ops and section names. + + Theses may be overridden in your tm.h file (if necessary) for your + particular assembler. The default values provided here correspond to + what is expected by "standard" AT&T System V.4 assemblers. */ + +#ifndef FILE_ASM_OP +#define FILE_ASM_OP "\t.file\t" +#endif +#ifndef SET_ASM_OP +#define SET_ASM_OP "\t.set\t" +#endif + +/* Pseudo-ops for pushing the current section onto the section stack (and + simultaneously changing to a new section) and for poping back to the + section we were in immediately before this one. Note that most svr4 + assemblers only maintain a one level stack... you can push all the + sections you want, but you can only pop out one level. (The sparc + svr4 assembler is an exception to this general rule.) That's + OK because we only use at most one level of the section stack herein. */ + +#ifndef PUSHSECTION_ASM_OP +#define PUSHSECTION_ASM_OP "\t.section\t" +#endif +#ifndef POPSECTION_ASM_OP +#define POPSECTION_ASM_OP "\t.previous" +#endif + +/* The default format used by the ASM_OUTPUT_PUSH_SECTION macro (see below) + to print the PUSHSECTION_ASM_OP and the section name. The default here + works for almost all svr4 assemblers, except for the sparc, where the + section name must be enclosed in double quotes. (See sparcv4.h.) */ + +#ifndef PUSHSECTION_FORMAT +#define PUSHSECTION_FORMAT "%s%s\n" +#endif + +#ifndef DEBUG_SECTION +#define DEBUG_SECTION ".debug" +#endif +#ifndef LINE_SECTION +#define LINE_SECTION ".line" +#endif +#ifndef DEBUG_SFNAMES_SECTION +#define DEBUG_SFNAMES_SECTION ".debug_sfnames" +#endif +#ifndef DEBUG_SRCINFO_SECTION +#define DEBUG_SRCINFO_SECTION ".debug_srcinfo" +#endif +#ifndef DEBUG_MACINFO_SECTION +#define DEBUG_MACINFO_SECTION ".debug_macinfo" +#endif +#ifndef DEBUG_PUBNAMES_SECTION +#define DEBUG_PUBNAMES_SECTION ".debug_pubnames" +#endif +#ifndef DEBUG_ARANGES_SECTION +#define DEBUG_ARANGES_SECTION ".debug_aranges" +#endif +#ifndef TEXT_SECTION_NAME +#define TEXT_SECTION_NAME ".text" +#endif +#ifndef DATA_SECTION_NAME +#define DATA_SECTION_NAME ".data" +#endif +#ifndef DATA1_SECTION_NAME +#define DATA1_SECTION_NAME ".data1" +#endif +#ifndef RODATA_SECTION_NAME +#define RODATA_SECTION_NAME ".rodata" +#endif +#ifndef RODATA1_SECTION_NAME +#define RODATA1_SECTION_NAME ".rodata1" +#endif +#ifndef BSS_SECTION_NAME +#define BSS_SECTION_NAME ".bss" +#endif + +/* Definitions of defaults for formats and names of various special + (artificial) labels which may be generated within this file (when + the -g options is used and DWARF_DEBUGGING_INFO is in effect. + + If necessary, these may be overridden from within your tm.h file, + but typically, you should never need to override these. + + These labels have been hacked (temporarily) so that they all begin with + a `.L' sequence so as to appease the stock sparc/svr4 assembler and the + stock m88k/svr4 assembler, both of which need to see .L at the start of + a label in order to prevent that label from going into the linker symbol + table). When I get time, I'll have to fix this the right way so that we + will use ASM_GENERATE_INTERNAL_LABEL and ASM_OUTPUT_INTERNAL_LABEL herein, + but that will require a rather massive set of changes. For the moment, + the following definitions out to produce the right results for all svr4 + and svr3 assemblers. -- rfg +*/ + +#ifndef TEXT_BEGIN_LABEL +#define TEXT_BEGIN_LABEL "*.L_text_b" +#endif +#ifndef TEXT_END_LABEL +#define TEXT_END_LABEL "*.L_text_e" +#endif + +#ifndef DATA_BEGIN_LABEL +#define DATA_BEGIN_LABEL "*.L_data_b" +#endif +#ifndef DATA_END_LABEL +#define DATA_END_LABEL "*.L_data_e" +#endif + +#ifndef DATA1_BEGIN_LABEL +#define DATA1_BEGIN_LABEL "*.L_data1_b" +#endif +#ifndef DATA1_END_LABEL +#define DATA1_END_LABEL "*.L_data1_e" +#endif + +#ifndef RODATA_BEGIN_LABEL +#define RODATA_BEGIN_LABEL "*.L_rodata_b" +#endif +#ifndef RODATA_END_LABEL +#define RODATA_END_LABEL "*.L_rodata_e" +#endif + +#ifndef RODATA1_BEGIN_LABEL +#define RODATA1_BEGIN_LABEL "*.L_rodata1_b" +#endif +#ifndef RODATA1_END_LABEL +#define RODATA1_END_LABEL "*.L_rodata1_e" +#endif + +#ifndef BSS_BEGIN_LABEL +#define BSS_BEGIN_LABEL "*.L_bss_b" +#endif +#ifndef BSS_END_LABEL +#define BSS_END_LABEL "*.L_bss_e" +#endif + +#ifndef LINE_BEGIN_LABEL +#define LINE_BEGIN_LABEL "*.L_line_b" +#endif +#ifndef LINE_LAST_ENTRY_LABEL +#define LINE_LAST_ENTRY_LABEL "*.L_line_last" +#endif +#ifndef LINE_END_LABEL +#define LINE_END_LABEL "*.L_line_e" +#endif + +#ifndef DEBUG_BEGIN_LABEL +#define DEBUG_BEGIN_LABEL "*.L_debug_b" +#endif +#ifndef SFNAMES_BEGIN_LABEL +#define SFNAMES_BEGIN_LABEL "*.L_sfnames_b" +#endif +#ifndef SRCINFO_BEGIN_LABEL +#define SRCINFO_BEGIN_LABEL "*.L_srcinfo_b" +#endif +#ifndef MACINFO_BEGIN_LABEL +#define MACINFO_BEGIN_LABEL "*.L_macinfo_b" +#endif + +#ifndef DEBUG_ARANGES_BEGIN_LABEL +#define DEBUG_ARANGES_BEGIN_LABEL "*.L_debug_aranges_begin" +#endif +#ifndef DEBUG_ARANGES_END_LABEL +#define DEBUG_ARANGES_END_LABEL "*.L_debug_aranges_end" +#endif + +#ifndef DIE_BEGIN_LABEL_FMT +#define DIE_BEGIN_LABEL_FMT "*.L_D%u" +#endif +#ifndef DIE_END_LABEL_FMT +#define DIE_END_LABEL_FMT "*.L_D%u_e" +#endif +#ifndef PUB_DIE_LABEL_FMT +#define PUB_DIE_LABEL_FMT "*.L_P%u" +#endif +#ifndef BLOCK_BEGIN_LABEL_FMT +#define BLOCK_BEGIN_LABEL_FMT "*.L_B%u" +#endif +#ifndef BLOCK_END_LABEL_FMT +#define BLOCK_END_LABEL_FMT "*.L_B%u_e" +#endif +#ifndef SS_BEGIN_LABEL_FMT +#define SS_BEGIN_LABEL_FMT "*.L_s%u" +#endif +#ifndef SS_END_LABEL_FMT +#define SS_END_LABEL_FMT "*.L_s%u_e" +#endif +#ifndef EE_BEGIN_LABEL_FMT +#define EE_BEGIN_LABEL_FMT "*.L_e%u" +#endif +#ifndef EE_END_LABEL_FMT +#define EE_END_LABEL_FMT "*.L_e%u_e" +#endif +#ifndef MT_BEGIN_LABEL_FMT +#define MT_BEGIN_LABEL_FMT "*.L_t%u" +#endif +#ifndef MT_END_LABEL_FMT +#define MT_END_LABEL_FMT "*.L_t%u_e" +#endif +#ifndef LOC_BEGIN_LABEL_FMT +#define LOC_BEGIN_LABEL_FMT "*.L_l%u" +#endif +#ifndef LOC_END_LABEL_FMT +#define LOC_END_LABEL_FMT "*.L_l%u_e" +#endif +#ifndef BOUND_BEGIN_LABEL_FMT +#define BOUND_BEGIN_LABEL_FMT "*.L_b%u_%u_%c" +#endif +#ifndef BOUND_END_LABEL_FMT +#define BOUND_END_LABEL_FMT "*.L_b%u_%u_%c_e" +#endif +#ifndef BODY_BEGIN_LABEL_FMT +#define BODY_BEGIN_LABEL_FMT "*.L_b%u" +#endif +#ifndef BODY_END_LABEL_FMT +#define BODY_END_LABEL_FMT "*.L_b%u_e" +#endif +#ifndef FUNC_END_LABEL_FMT +#define FUNC_END_LABEL_FMT "*.L_f%u_e" +#endif +#ifndef TYPE_NAME_FMT +#define TYPE_NAME_FMT "*.L_T%u" +#endif +#ifndef DECL_NAME_FMT +#define DECL_NAME_FMT "*.L_E%u" +#endif +#ifndef LINE_CODE_LABEL_FMT +#define LINE_CODE_LABEL_FMT "*.L_LC%u" +#endif +#ifndef SFNAMES_ENTRY_LABEL_FMT +#define SFNAMES_ENTRY_LABEL_FMT "*.L_F%u" +#endif +#ifndef LINE_ENTRY_LABEL_FMT +#define LINE_ENTRY_LABEL_FMT "*.L_LE%u" +#endif + +/* Definitions of defaults for various types of primitive assembly language + output operations. + + If necessary, these may be overridden from within your tm.h file, + but typically, you shouldn't need to override these. */ + +#ifndef ASM_OUTPUT_PUSH_SECTION +#define ASM_OUTPUT_PUSH_SECTION(FILE, SECTION) \ + fprintf ((FILE), PUSHSECTION_FORMAT, PUSHSECTION_ASM_OP, SECTION) +#endif + +#ifndef ASM_OUTPUT_POP_SECTION +#define ASM_OUTPUT_POP_SECTION(FILE) \ + fprintf ((FILE), "%s\n", POPSECTION_ASM_OP) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA2 +#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \ + dw2_asm_output_delta (2, LABEL1, LABEL2, NULL) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA4 +#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \ + dw2_asm_output_delta (4, LABEL1, LABEL2, NULL) +#endif + +#ifndef ASM_OUTPUT_DWARF_TAG +#define ASM_OUTPUT_DWARF_TAG(FILE,TAG) \ + dw2_asm_output_data (2, TAG, "%s", dwarf_tag_name (TAG)); +#endif + +#ifndef ASM_OUTPUT_DWARF_ATTRIBUTE +#define ASM_OUTPUT_DWARF_ATTRIBUTE(FILE,ATTR) \ + dw2_asm_output_data (2, ATTR, "%s", dwarf_attr_name (ATTR)) +#endif + +#ifndef ASM_OUTPUT_DWARF_STACK_OP +#define ASM_OUTPUT_DWARF_STACK_OP(FILE,OP) \ + dw2_asm_output_data (1, OP, "%s", dwarf_stack_op_name (OP)) +#endif + +#ifndef ASM_OUTPUT_DWARF_FUND_TYPE +#define ASM_OUTPUT_DWARF_FUND_TYPE(FILE,FT) \ + dw2_asm_output_data (2, FT, "%s", dwarf_fund_type_name (FT)) +#endif + +#ifndef ASM_OUTPUT_DWARF_FMT_BYTE +#define ASM_OUTPUT_DWARF_FMT_BYTE(FILE,FMT) \ + dw2_asm_output_data (1, FMT, "%s", dwarf_fmt_byte_name (FMT)); +#endif + +#ifndef ASM_OUTPUT_DWARF_TYPE_MODIFIER +#define ASM_OUTPUT_DWARF_TYPE_MODIFIER(FILE,MOD) \ + dw2_asm_output_data (1, MOD, "%s", dwarf_typemod_name (MOD)); +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR +#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \ + dw2_asm_output_addr (4, LABEL, NULL) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR_CONST +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ + dw2_asm_output_addr_rtx (4, RTX, NULL) +#endif + +#ifndef ASM_OUTPUT_DWARF_REF +#define ASM_OUTPUT_DWARF_REF(FILE,LABEL) \ + dw2_asm_output_addr (4, LABEL, NULL) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA1 +#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \ + dw2_asm_output_data (1, VALUE, NULL) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA2 +#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \ + dw2_asm_output_data (2, VALUE, NULL) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA4 +#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \ + dw2_asm_output_data (4, VALUE, NULL) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA8 +#define ASM_OUTPUT_DWARF_DATA8(FILE,HIGH_VALUE,LOW_VALUE) \ + dw2_asm_output_data (8, VALUE, NULL) +#endif + +/* ASM_OUTPUT_DWARF_STRING is defined to output an ascii string, but to + NOT issue a trailing newline. We define ASM_OUTPUT_DWARF_STRING_NEWLINE + based on whether ASM_OUTPUT_DWARF_STRING is defined or not. If it is + defined, we call it, then issue the line feed. If not, we supply a + default definition of calling ASM_OUTPUT_ASCII */ + +#ifndef ASM_OUTPUT_DWARF_STRING +#define ASM_OUTPUT_DWARF_STRING_NEWLINE(FILE,P) \ + ASM_OUTPUT_ASCII ((FILE), P, strlen (P)+1) +#else +#define ASM_OUTPUT_DWARF_STRING_NEWLINE(FILE,P) \ + ASM_OUTPUT_DWARF_STRING (FILE,P), ASM_OUTPUT_DWARF_STRING (FILE,"\n") +#endif + + +/* The debug hooks structure. */ +const struct gcc_debug_hooks dwarf_debug_hooks = +{ + dwarfout_init, + dwarfout_finish, + dwarfout_define, + dwarfout_undef, + dwarfout_start_source_file_check, + dwarfout_end_source_file_check, + dwarfout_begin_block, + dwarfout_end_block, + debug_true_tree, /* ignore_block */ + dwarfout_source_line, /* source_line */ + dwarfout_source_line, /* begin_prologue */ + dwarfout_end_prologue, + dwarfout_end_epilogue, + debug_nothing_tree, /* begin_function */ + dwarfout_end_function, + dwarfout_function_decl, + dwarfout_global_decl, + dwarfout_deferred_inline_function, + debug_nothing_tree, /* outlining_inline_function */ + debug_nothing_rtx /* label */ +}; + +/************************ general utility functions **************************/ + +static inline int +is_pseudo_reg (rtl) + rtx rtl; +{ + return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)) + || ((GET_CODE (rtl) == SUBREG) + && (REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER))); +} + +static inline tree +type_main_variant (type) + tree type; +{ + type = TYPE_MAIN_VARIANT (type); + + /* There really should be only one main variant among any group of variants + of a given type (and all of the MAIN_VARIANT values for all members of + the group should point to that one type) but sometimes the C front-end + messes this up for array types, so we work around that bug here. */ + + if (TREE_CODE (type) == ARRAY_TYPE) + { + while (type != TYPE_MAIN_VARIANT (type)) + type = TYPE_MAIN_VARIANT (type); + } + + return type; +} + +/* Return nonzero if the given type node represents a tagged type. */ + +static inline int +is_tagged_type (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + + return (code == RECORD_TYPE || code == UNION_TYPE + || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE); +} + +static const char * +dwarf_tag_name (tag) + unsigned tag; +{ + switch (tag) + { + case TAG_padding: return "TAG_padding"; + case TAG_array_type: return "TAG_array_type"; + case TAG_class_type: return "TAG_class_type"; + case TAG_entry_point: return "TAG_entry_point"; + case TAG_enumeration_type: return "TAG_enumeration_type"; + case TAG_formal_parameter: return "TAG_formal_parameter"; + case TAG_global_subroutine: return "TAG_global_subroutine"; + case TAG_global_variable: return "TAG_global_variable"; + case TAG_label: return "TAG_label"; + case TAG_lexical_block: return "TAG_lexical_block"; + case TAG_local_variable: return "TAG_local_variable"; + case TAG_member: return "TAG_member"; + case TAG_pointer_type: return "TAG_pointer_type"; + case TAG_reference_type: return "TAG_reference_type"; + case TAG_compile_unit: return "TAG_compile_unit"; + case TAG_string_type: return "TAG_string_type"; + case TAG_structure_type: return "TAG_structure_type"; + case TAG_subroutine: return "TAG_subroutine"; + case TAG_subroutine_type: return "TAG_subroutine_type"; + case TAG_typedef: return "TAG_typedef"; + case TAG_union_type: return "TAG_union_type"; + case TAG_unspecified_parameters: return "TAG_unspecified_parameters"; + case TAG_variant: return "TAG_variant"; + case TAG_common_block: return "TAG_common_block"; + case TAG_common_inclusion: return "TAG_common_inclusion"; + case TAG_inheritance: return "TAG_inheritance"; + case TAG_inlined_subroutine: return "TAG_inlined_subroutine"; + case TAG_module: return "TAG_module"; + case TAG_ptr_to_member_type: return "TAG_ptr_to_member_type"; + case TAG_set_type: return "TAG_set_type"; + case TAG_subrange_type: return "TAG_subrange_type"; + case TAG_with_stmt: return "TAG_with_stmt"; + + /* GNU extensions. */ + + case TAG_format_label: return "TAG_format_label"; + case TAG_namelist: return "TAG_namelist"; + case TAG_function_template: return "TAG_function_template"; + case TAG_class_template: return "TAG_class_template"; + + default: return "TAG_<unknown>"; + } +} + +static const char * +dwarf_attr_name (attr) + unsigned attr; +{ + switch (attr) + { + case AT_sibling: return "AT_sibling"; + case AT_location: return "AT_location"; + case AT_name: return "AT_name"; + case AT_fund_type: return "AT_fund_type"; + case AT_mod_fund_type: return "AT_mod_fund_type"; + case AT_user_def_type: return "AT_user_def_type"; + case AT_mod_u_d_type: return "AT_mod_u_d_type"; + case AT_ordering: return "AT_ordering"; + case AT_subscr_data: return "AT_subscr_data"; + case AT_byte_size: return "AT_byte_size"; + case AT_bit_offset: return "AT_bit_offset"; + case AT_bit_size: return "AT_bit_size"; + case AT_element_list: return "AT_element_list"; + case AT_stmt_list: return "AT_stmt_list"; + case AT_low_pc: return "AT_low_pc"; + case AT_high_pc: return "AT_high_pc"; + case AT_language: return "AT_language"; + case AT_member: return "AT_member"; + case AT_discr: return "AT_discr"; + case AT_discr_value: return "AT_discr_value"; + case AT_string_length: return "AT_string_length"; + case AT_common_reference: return "AT_common_reference"; + case AT_comp_dir: return "AT_comp_dir"; + case AT_const_value_string: return "AT_const_value_string"; + case AT_const_value_data2: return "AT_const_value_data2"; + case AT_const_value_data4: return "AT_const_value_data4"; + case AT_const_value_data8: return "AT_const_value_data8"; + case AT_const_value_block2: return "AT_const_value_block2"; + case AT_const_value_block4: return "AT_const_value_block4"; + case AT_containing_type: return "AT_containing_type"; + case AT_default_value_addr: return "AT_default_value_addr"; + case AT_default_value_data2: return "AT_default_value_data2"; + case AT_default_value_data4: return "AT_default_value_data4"; + case AT_default_value_data8: return "AT_default_value_data8"; + case AT_default_value_string: return "AT_default_value_string"; + case AT_friends: return "AT_friends"; + case AT_inline: return "AT_inline"; + case AT_is_optional: return "AT_is_optional"; + case AT_lower_bound_ref: return "AT_lower_bound_ref"; + case AT_lower_bound_data2: return "AT_lower_bound_data2"; + case AT_lower_bound_data4: return "AT_lower_bound_data4"; + case AT_lower_bound_data8: return "AT_lower_bound_data8"; + case AT_private: return "AT_private"; + case AT_producer: return "AT_producer"; + case AT_program: return "AT_program"; + case AT_protected: return "AT_protected"; + case AT_prototyped: return "AT_prototyped"; + case AT_public: return "AT_public"; + case AT_pure_virtual: return "AT_pure_virtual"; + case AT_return_addr: return "AT_return_addr"; + case AT_abstract_origin: return "AT_abstract_origin"; + case AT_start_scope: return "AT_start_scope"; + case AT_stride_size: return "AT_stride_size"; + case AT_upper_bound_ref: return "AT_upper_bound_ref"; + case AT_upper_bound_data2: return "AT_upper_bound_data2"; + case AT_upper_bound_data4: return "AT_upper_bound_data4"; + case AT_upper_bound_data8: return "AT_upper_bound_data8"; + case AT_virtual: return "AT_virtual"; + + /* GNU extensions */ + + case AT_sf_names: return "AT_sf_names"; + case AT_src_info: return "AT_src_info"; + case AT_mac_info: return "AT_mac_info"; + case AT_src_coords: return "AT_src_coords"; + case AT_body_begin: return "AT_body_begin"; + case AT_body_end: return "AT_body_end"; + + default: return "AT_<unknown>"; + } +} + +static const char * +dwarf_stack_op_name (op) + unsigned op; +{ + switch (op) + { + case OP_REG: return "OP_REG"; + case OP_BASEREG: return "OP_BASEREG"; + case OP_ADDR: return "OP_ADDR"; + case OP_CONST: return "OP_CONST"; + case OP_DEREF2: return "OP_DEREF2"; + case OP_DEREF4: return "OP_DEREF4"; + case OP_ADD: return "OP_ADD"; + default: return "OP_<unknown>"; + } +} + +static const char * +dwarf_typemod_name (mod) + unsigned mod; +{ + switch (mod) + { + case MOD_pointer_to: return "MOD_pointer_to"; + case MOD_reference_to: return "MOD_reference_to"; + case MOD_const: return "MOD_const"; + case MOD_volatile: return "MOD_volatile"; + default: return "MOD_<unknown>"; + } +} + +static const char * +dwarf_fmt_byte_name (fmt) + unsigned fmt; +{ + switch (fmt) + { + case FMT_FT_C_C: return "FMT_FT_C_C"; + case FMT_FT_C_X: return "FMT_FT_C_X"; + case FMT_FT_X_C: return "FMT_FT_X_C"; + case FMT_FT_X_X: return "FMT_FT_X_X"; + case FMT_UT_C_C: return "FMT_UT_C_C"; + case FMT_UT_C_X: return "FMT_UT_C_X"; + case FMT_UT_X_C: return "FMT_UT_X_C"; + case FMT_UT_X_X: return "FMT_UT_X_X"; + case FMT_ET: return "FMT_ET"; + default: return "FMT_<unknown>"; + } +} + +static const char * +dwarf_fund_type_name (ft) + unsigned ft; +{ + switch (ft) + { + case FT_char: return "FT_char"; + case FT_signed_char: return "FT_signed_char"; + case FT_unsigned_char: return "FT_unsigned_char"; + case FT_short: return "FT_short"; + case FT_signed_short: return "FT_signed_short"; + case FT_unsigned_short: return "FT_unsigned_short"; + case FT_integer: return "FT_integer"; + case FT_signed_integer: return "FT_signed_integer"; + case FT_unsigned_integer: return "FT_unsigned_integer"; + case FT_long: return "FT_long"; + case FT_signed_long: return "FT_signed_long"; + case FT_unsigned_long: return "FT_unsigned_long"; + case FT_pointer: return "FT_pointer"; + case FT_float: return "FT_float"; + case FT_dbl_prec_float: return "FT_dbl_prec_float"; + case FT_ext_prec_float: return "FT_ext_prec_float"; + case FT_complex: return "FT_complex"; + case FT_dbl_prec_complex: return "FT_dbl_prec_complex"; + case FT_void: return "FT_void"; + case FT_boolean: return "FT_boolean"; + case FT_ext_prec_complex: return "FT_ext_prec_complex"; + case FT_label: return "FT_label"; + + /* GNU extensions. */ + + case FT_long_long: return "FT_long_long"; + case FT_signed_long_long: return "FT_signed_long_long"; + case FT_unsigned_long_long: return "FT_unsigned_long_long"; + + case FT_int8: return "FT_int8"; + case FT_signed_int8: return "FT_signed_int8"; + case FT_unsigned_int8: return "FT_unsigned_int8"; + case FT_int16: return "FT_int16"; + case FT_signed_int16: return "FT_signed_int16"; + case FT_unsigned_int16: return "FT_unsigned_int16"; + case FT_int32: return "FT_int32"; + case FT_signed_int32: return "FT_signed_int32"; + case FT_unsigned_int32: return "FT_unsigned_int32"; + case FT_int64: return "FT_int64"; + case FT_signed_int64: return "FT_signed_int64"; + case FT_unsigned_int64: return "FT_unsigned_int64"; + case FT_int128: return "FT_int128"; + case FT_signed_int128: return "FT_signed_int128"; + case FT_unsigned_int128: return "FT_unsigned_int128"; + + case FT_real32: return "FT_real32"; + case FT_real64: return "FT_real64"; + case FT_real96: return "FT_real96"; + case FT_real128: return "FT_real128"; + + default: return "FT_<unknown>"; + } +} + +/* Determine the "ultimate origin" of a decl. The decl may be an + inlined instance of an inlined instance of a decl which is local + to an inline function, so we have to trace all of the way back + through the origin chain to find out what sort of node actually + served as the original seed for the given block. */ + +static tree +decl_ultimate_origin (decl) + tree decl; +{ +#ifdef ENABLE_CHECKING + if (DECL_FROM_INLINE (DECL_ORIGIN (decl))) + /* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the + most distant ancestor, this should never happen. */ + abort (); +#endif + + return DECL_ABSTRACT_ORIGIN (decl); +} + +/* Determine the "ultimate origin" of a block. The block may be an + inlined instance of an inlined instance of a block which is local + to an inline function, so we have to trace all of the way back + through the origin chain to find out what sort of node actually + served as the original seed for the given block. */ + +static tree +block_ultimate_origin (block) + tree block; +{ + tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block); + + if (immediate_origin == NULL) + return NULL; + else + { + tree ret_val; + tree lookahead = immediate_origin; + + do + { + ret_val = lookahead; + lookahead = (TREE_CODE (ret_val) == BLOCK) + ? BLOCK_ABSTRACT_ORIGIN (ret_val) + : NULL; + } + while (lookahead != NULL && lookahead != ret_val); + return ret_val; + } +} + +/* Get the class to which DECL belongs, if any. In g++, the DECL_CONTEXT + of a virtual function may refer to a base class, so we check the 'this' + parameter. */ + +static tree +decl_class_context (decl) + tree decl; +{ + tree context = NULL_TREE; + if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl)) + context = DECL_CONTEXT (decl); + else + context = TYPE_MAIN_VARIANT + (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))))); + + if (context && !TYPE_P (context)) + context = NULL_TREE; + + return context; +} + +#if 0 +static void +output_unsigned_leb128 (value) + unsigned long value; +{ + unsigned long orig_value = value; + + do + { + unsigned byte = (value & 0x7f); + + value >>= 7; + if (value != 0) /* more bytes to follow */ + byte |= 0x80; + dw2_asm_output_data (1, byte, "\t%s ULEB128 number - value = %lu", + orig_value); + } + while (value != 0); +} + +static void +output_signed_leb128 (value) + long value; +{ + long orig_value = value; + int negative = (value < 0); + int more; + + do + { + unsigned byte = (value & 0x7f); + + value >>= 7; + if (negative) + value |= 0xfe000000; /* manually sign extend */ + if (((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) == 1))) + more = 0; + else + { + byte |= 0x80; + more = 1; + } + dw2_asm_output_data (1, byte, "\t%s SLEB128 number - value = %ld", + orig_value); + } + while (more); +} +#endif + +/**************** utility functions for attribute functions ******************/ + +/* Given a pointer to a tree node for some type, return a Dwarf fundamental + type code for the given type. + + This routine must only be called for GCC type nodes that correspond to + Dwarf fundamental types. + + The current Dwarf draft specification calls for Dwarf fundamental types + to accurately reflect the fact that a given type was either a "plain" + integral type or an explicitly "signed" integral type. Unfortunately, + we can't always do this, because GCC may already have thrown away the + information about the precise way in which the type was originally + specified, as in: + + typedef signed int my_type; + + struct s { my_type f; }; + + Since we may be stuck here without enough information to do exactly + what is called for in the Dwarf draft specification, we do the best + that we can under the circumstances and always use the "plain" integral + fundamental type codes for int, short, and long types. That's probably + good enough. The additional accuracy called for in the current DWARF + draft specification is probably never even useful in practice. */ + +static int +fundamental_type_code (type) + tree type; +{ + if (TREE_CODE (type) == ERROR_MARK) + return 0; + + switch (TREE_CODE (type)) + { + case ERROR_MARK: + return FT_void; + + case VOID_TYPE: + return FT_void; + + case INTEGER_TYPE: + /* Carefully distinguish all the standard types of C, + without messing up if the language is not C. + Note that we check only for the names that contain spaces; + other names might occur by coincidence in other languages. */ + if (TYPE_NAME (type) != 0 + && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (type)) != 0 + && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE) + { + const char *const name = + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); + + if (!strcmp (name, "unsigned char")) + return FT_unsigned_char; + if (!strcmp (name, "signed char")) + return FT_signed_char; + if (!strcmp (name, "unsigned int")) + return FT_unsigned_integer; + if (!strcmp (name, "short int")) + return FT_short; + if (!strcmp (name, "short unsigned int")) + return FT_unsigned_short; + if (!strcmp (name, "long int")) + return FT_long; + if (!strcmp (name, "long unsigned int")) + return FT_unsigned_long; + if (!strcmp (name, "long long int")) + return FT_long_long; /* Not grok'ed by svr4 SDB */ + if (!strcmp (name, "long long unsigned int")) + return FT_unsigned_long_long; /* Not grok'ed by svr4 SDB */ + } + + /* Most integer types will be sorted out above, however, for the + sake of special `array index' integer types, the following code + is also provided. */ + + if (TYPE_PRECISION (type) == INT_TYPE_SIZE) + return (TREE_UNSIGNED (type) ? FT_unsigned_integer : FT_integer); + + if (TYPE_PRECISION (type) == LONG_TYPE_SIZE) + return (TREE_UNSIGNED (type) ? FT_unsigned_long : FT_long); + + if (TYPE_PRECISION (type) == LONG_LONG_TYPE_SIZE) + return (TREE_UNSIGNED (type) ? FT_unsigned_long_long : FT_long_long); + + if (TYPE_PRECISION (type) == SHORT_TYPE_SIZE) + return (TREE_UNSIGNED (type) ? FT_unsigned_short : FT_short); + + if (TYPE_PRECISION (type) == CHAR_TYPE_SIZE) + return (TREE_UNSIGNED (type) ? FT_unsigned_char : FT_char); + + if (TYPE_MODE (type) == TImode) + return (TREE_UNSIGNED (type) ? FT_unsigned_int128 : FT_int128); + + /* In C++, __java_boolean is an INTEGER_TYPE with precision == 1 */ + if (TYPE_PRECISION (type) == 1) + return FT_boolean; + + abort (); + + case REAL_TYPE: + /* Carefully distinguish all the standard types of C, + without messing up if the language is not C. */ + if (TYPE_NAME (type) != 0 + && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (type)) != 0 + && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE) + { + const char *const name = + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); + + /* Note that here we can run afoul of a serious bug in "classic" + svr4 SDB debuggers. They don't seem to understand the + FT_ext_prec_float type (even though they should). */ + + if (!strcmp (name, "long double")) + return FT_ext_prec_float; + } + + if (TYPE_PRECISION (type) == DOUBLE_TYPE_SIZE) + { + /* On the SH, when compiling with -m3e or -m4-single-only, both + float and double are 32 bits. But since the debugger doesn't + know about the subtarget, it always thinks double is 64 bits. + So we have to tell the debugger that the type is float to + make the output of the 'print' command etc. readable. */ + if (DOUBLE_TYPE_SIZE == FLOAT_TYPE_SIZE && FLOAT_TYPE_SIZE == 32) + return FT_float; + return FT_dbl_prec_float; + } + if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE) + return FT_float; + + /* Note that here we can run afoul of a serious bug in "classic" + svr4 SDB debuggers. They don't seem to understand the + FT_ext_prec_float type (even though they should). */ + + if (TYPE_PRECISION (type) == LONG_DOUBLE_TYPE_SIZE) + return FT_ext_prec_float; + abort (); + + case COMPLEX_TYPE: + return FT_complex; /* GNU FORTRAN COMPLEX type. */ + + case CHAR_TYPE: + return FT_char; /* GNU Pascal CHAR type. Not used in C. */ + + case BOOLEAN_TYPE: + return FT_boolean; /* GNU FORTRAN BOOLEAN type. */ + + default: + abort (); /* No other TREE_CODEs are Dwarf fundamental types. */ + } + return 0; +} + +/* Given a pointer to an arbitrary ..._TYPE tree node, return a pointer to + the Dwarf "root" type for the given input type. The Dwarf "root" type + of a given type is generally the same as the given type, except that if + the given type is a pointer or reference type, then the root type of + the given type is the root type of the "basis" type for the pointer or + reference type. (This definition of the "root" type is recursive.) + Also, the root type of a `const' qualified type or a `volatile' + qualified type is the root type of the given type without the + qualifiers. */ + +static tree +root_type_1 (type, count) + tree type; + int count; +{ + /* Give up after searching 1000 levels, in case this is a recursive + pointer type. Such types are possible in Ada, but it is not possible + to represent them in DWARF1 debug info. */ + if (count > 1000) + return error_mark_node; + + switch (TREE_CODE (type)) + { + case ERROR_MARK: + return error_mark_node; + + case POINTER_TYPE: + case REFERENCE_TYPE: + return root_type_1 (TREE_TYPE (type), count+1); + + default: + return type; + } +} + +static tree +root_type (type) + tree type; +{ + type = root_type_1 (type, 0); + if (type != error_mark_node) + type = type_main_variant (type); + return type; +} + +/* Given a pointer to an arbitrary ..._TYPE tree node, write out a sequence + of zero or more Dwarf "type-modifier" bytes applicable to the type. */ + +static void +write_modifier_bytes_1 (type, decl_const, decl_volatile, count) + tree type; + int decl_const; + int decl_volatile; + int count; +{ + if (TREE_CODE (type) == ERROR_MARK) + return; + + /* Give up after searching 1000 levels, in case this is a recursive + pointer type. Such types are possible in Ada, but it is not possible + to represent them in DWARF1 debug info. */ + if (count > 1000) + return; + + if (TYPE_READONLY (type) || decl_const) + ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_const); + if (TYPE_VOLATILE (type) || decl_volatile) + ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_volatile); + switch (TREE_CODE (type)) + { + case POINTER_TYPE: + ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_pointer_to); + write_modifier_bytes_1 (TREE_TYPE (type), 0, 0, count+1); + return; + + case REFERENCE_TYPE: + ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_reference_to); + write_modifier_bytes_1 (TREE_TYPE (type), 0, 0, count+1); + return; + + case ERROR_MARK: + default: + return; + } +} + +static void +write_modifier_bytes (type, decl_const, decl_volatile) + tree type; + int decl_const; + int decl_volatile; +{ + write_modifier_bytes_1 (type, decl_const, decl_volatile, 0); +} + +/* Given a pointer to an arbitrary ..._TYPE tree node, return nonzero if the + given input type is a Dwarf "fundamental" type. Otherwise return zero. */ + +static inline int +type_is_fundamental (type) + tree type; +{ + switch (TREE_CODE (type)) + { + case ERROR_MARK: + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case COMPLEX_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + return 1; + + case SET_TYPE: + case ARRAY_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + case ENUMERAL_TYPE: + case FUNCTION_TYPE: + case METHOD_TYPE: + case POINTER_TYPE: + case REFERENCE_TYPE: + case FILE_TYPE: + case OFFSET_TYPE: + case LANG_TYPE: + case VECTOR_TYPE: + return 0; + + default: + abort (); + } + return 0; +} + +/* Given a pointer to some ..._DECL tree node, generate an assembly language + equate directive which will associate a symbolic name with the current DIE. + + The name used is an artificial label generated from the DECL_UID number + associated with the given decl node. The name it gets equated to is the + symbolic label that we (previously) output at the start of the DIE that + we are currently generating. + + Calling this function while generating some "decl related" form of DIE + makes it possible to later refer to the DIE which represents the given + decl simply by re-generating the symbolic name from the ..._DECL node's + UID number. */ + +static void +equate_decl_number_to_die_number (decl) + tree decl; +{ + /* In the case where we are generating a DIE for some ..._DECL node + which represents either some inline function declaration or some + entity declared within an inline function declaration/definition, + setup a symbolic name for the current DIE so that we have a name + for this DIE that we can easily refer to later on within + AT_abstract_origin attributes. */ + + char decl_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char die_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + sprintf (decl_label, DECL_NAME_FMT, DECL_UID (decl)); + sprintf (die_label, DIE_BEGIN_LABEL_FMT, current_dienum); + ASM_OUTPUT_DEF (asm_out_file, decl_label, die_label); +} + +/* Given a pointer to some ..._TYPE tree node, generate an assembly language + equate directive which will associate a symbolic name with the current DIE. + + The name used is an artificial label generated from the TYPE_UID number + associated with the given type node. The name it gets equated to is the + symbolic label that we (previously) output at the start of the DIE that + we are currently generating. + + Calling this function while generating some "type related" form of DIE + makes it easy to later refer to the DIE which represents the given type + simply by re-generating the alternative name from the ..._TYPE node's + UID number. */ + +static inline void +equate_type_number_to_die_number (type) + tree type; +{ + char type_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char die_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + /* We are generating a DIE to represent the main variant of this type + (i.e the type without any const or volatile qualifiers) so in order + to get the equate to come out right, we need to get the main variant + itself here. */ + + type = type_main_variant (type); + + sprintf (type_label, TYPE_NAME_FMT, TYPE_UID (type)); + sprintf (die_label, DIE_BEGIN_LABEL_FMT, current_dienum); + ASM_OUTPUT_DEF (asm_out_file, type_label, die_label); +} + +static void +output_reg_number (rtl) + rtx rtl; +{ + unsigned regno = REGNO (rtl); + + if (regno >= DWARF_FRAME_REGISTERS) + { + warning_with_decl (dwarf_last_decl, + "internal regno botch: `%s' has regno = %d\n", + regno); + regno = 0; + } + dw2_assemble_integer (4, GEN_INT (DBX_REGISTER_NUMBER (regno))); + if (flag_debug_asm) + { + fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START); + PRINT_REG (rtl, 0, asm_out_file); + } + fputc ('\n', asm_out_file); +} + +/* The following routine is a nice and simple transducer. It converts the + RTL for a variable or parameter (resident in memory) into an equivalent + Dwarf representation of a mechanism for getting the address of that same + variable onto the top of a hypothetical "address evaluation" stack. + + When creating memory location descriptors, we are effectively trans- + forming the RTL for a memory-resident object into its Dwarf postfix + expression equivalent. This routine just recursively descends an + RTL tree, turning it into Dwarf postfix code as it goes. */ + +static void +output_mem_loc_descriptor (rtl) + rtx rtl; +{ + /* Note that for a dynamically sized array, the location we will + generate a description of here will be the lowest numbered location + which is actually within the array. That's *not* necessarily the + same as the zeroth element of the array. */ + +#ifdef ASM_SIMPLIFY_DWARF_ADDR + rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl); +#endif + + switch (GET_CODE (rtl)) + { + case SUBREG: + + /* The case of a subreg may arise when we have a local (register) + variable or a formal (register) parameter which doesn't quite + fill up an entire register. For now, just assume that it is + legitimate to make the Dwarf info refer to the whole register + which contains the given subreg. */ + + rtl = SUBREG_REG (rtl); + /* Drop thru. */ + + case REG: + + /* Whenever a register number forms a part of the description of + the method for calculating the (dynamic) address of a memory + resident object, DWARF rules require the register number to + be referred to as a "base register". This distinction is not + based in any way upon what category of register the hardware + believes the given register belongs to. This is strictly + DWARF terminology we're dealing with here. + + Note that in cases where the location of a memory-resident data + object could be expressed as: + + OP_ADD (OP_BASEREG (basereg), OP_CONST (0)) + + the actual DWARF location descriptor that we generate may just + be OP_BASEREG (basereg). This may look deceptively like the + object in question was allocated to a register (rather than + in memory) so DWARF consumers need to be aware of the subtle + distinction between OP_REG and OP_BASEREG. */ + + ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_BASEREG); + output_reg_number (rtl); + break; + + case MEM: + output_mem_loc_descriptor (XEXP (rtl, 0)); + ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_DEREF4); + break; + + case CONST: + case SYMBOL_REF: + ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_ADDR); + ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, rtl); + break; + + case PLUS: + output_mem_loc_descriptor (XEXP (rtl, 0)); + output_mem_loc_descriptor (XEXP (rtl, 1)); + ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_ADD); + break; + + case CONST_INT: + ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_CONST); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, INTVAL (rtl)); + break; + + case MULT: + /* If a pseudo-reg is optimized away, it is possible for it to + be replaced with a MEM containing a multiply. Use a GNU extension + to describe it. */ + output_mem_loc_descriptor (XEXP (rtl, 0)); + output_mem_loc_descriptor (XEXP (rtl, 1)); + ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_MULT); + break; + + default: + abort (); + } +} + +/* Output a proper Dwarf location descriptor for a variable or parameter + which is either allocated in a register or in a memory location. For + a register, we just generate an OP_REG and the register number. For a + memory location we provide a Dwarf postfix expression describing how to + generate the (dynamic) address of the object onto the address stack. */ + +static void +output_loc_descriptor (rtl) + rtx rtl; +{ + switch (GET_CODE (rtl)) + { + case SUBREG: + + /* The case of a subreg may arise when we have a local (register) + variable or a formal (register) parameter which doesn't quite + fill up an entire register. For now, just assume that it is + legitimate to make the Dwarf info refer to the whole register + which contains the given subreg. */ + + rtl = SUBREG_REG (rtl); + /* Drop thru. */ + + case REG: + ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_REG); + output_reg_number (rtl); + break; + + case MEM: + output_mem_loc_descriptor (XEXP (rtl, 0)); + break; + + default: + abort (); /* Should never happen */ + } +} + +/* Given a tree node describing an array bound (either lower or upper) + output a representation for that bound. */ + +static void +output_bound_representation (bound, dim_num, u_or_l) + tree bound; + unsigned dim_num; /* For multi-dimensional arrays. */ + char u_or_l; /* Designates upper or lower bound. */ +{ + switch (TREE_CODE (bound)) + { + + case ERROR_MARK: + return; + + /* All fixed-bounds are represented by INTEGER_CST nodes. */ + + case INTEGER_CST: + if (host_integerp (bound, 0)) + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, tree_low_cst (bound, 0)); + break; + + default: + + /* Dynamic bounds may be represented by NOP_EXPR nodes containing + SAVE_EXPR nodes, in which case we can do something, or as + an expression, which we cannot represent. */ + { + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + sprintf (begin_label, BOUND_BEGIN_LABEL_FMT, + current_dienum, dim_num, u_or_l); + + sprintf (end_label, BOUND_END_LABEL_FMT, + current_dienum, dim_num, u_or_l); + + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label); + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + + /* If optimization is turned on, the SAVE_EXPRs that describe + how to access the upper bound values are essentially bogus. + They only describe (at best) how to get at these values at + the points in the generated code right after they have just + been computed. Worse yet, in the typical case, the upper + bound values will not even *be* computed in the optimized + code, so these SAVE_EXPRs are entirely bogus. + + In order to compensate for this fact, we check here to see + if optimization is enabled, and if so, we effectively create + an empty location description for the (unknown and unknowable) + upper bound. + + This should not cause too much trouble for existing (stupid?) + debuggers because they have to deal with empty upper bounds + location descriptions anyway in order to be able to deal with + incomplete array types. + + Of course an intelligent debugger (GDB?) should be able to + comprehend that a missing upper bound specification in a + array type used for a storage class `auto' local array variable + indicates that the upper bound is both unknown (at compile- + time) and unknowable (at run-time) due to optimization. */ + + if (! optimize) + { + while (TREE_CODE (bound) == NOP_EXPR + || TREE_CODE (bound) == CONVERT_EXPR) + bound = TREE_OPERAND (bound, 0); + + if (TREE_CODE (bound) == SAVE_EXPR + && SAVE_EXPR_RTL (bound)) + output_loc_descriptor + (eliminate_regs (SAVE_EXPR_RTL (bound), 0, NULL_RTX)); + } + + ASM_OUTPUT_LABEL (asm_out_file, end_label); + } + break; + + } +} + +/* Recursive function to output a sequence of value/name pairs for + enumeration constants in reversed order. This is called from + enumeration_type_die. */ + +static void +output_enumeral_list (link) + tree link; +{ + if (link) + { + output_enumeral_list (TREE_CHAIN (link)); + + if (host_integerp (TREE_VALUE (link), 0)) + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, + tree_low_cst (TREE_VALUE (link), 0)); + + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, + IDENTIFIER_POINTER (TREE_PURPOSE (link))); + } +} + +/* Given an unsigned value, round it up to the lowest multiple of `boundary' + which is not less than the value itself. */ + +static inline HOST_WIDE_INT +ceiling (value, boundary) + HOST_WIDE_INT value; + unsigned int boundary; +{ + return (((value + boundary - 1) / boundary) * boundary); +} + +/* Given a pointer to what is assumed to be a FIELD_DECL node, return a + pointer to the declared type for the relevant field variable, or return + `integer_type_node' if the given node turns out to be an ERROR_MARK node. */ + +static inline tree +field_type (decl) + tree decl; +{ + tree type; + + if (TREE_CODE (decl) == ERROR_MARK) + return integer_type_node; + + type = DECL_BIT_FIELD_TYPE (decl); + if (type == NULL) + type = TREE_TYPE (decl); + return type; +} + +/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE + node, return the alignment in bits for the type, or else return + BITS_PER_WORD if the node actually turns out to be an ERROR_MARK node. */ + +static inline unsigned int +simple_type_align_in_bits (type) + tree type; +{ + return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD; +} + +/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE + node, return the size in bits for the type if it is a constant, or + else return the alignment for the type if the type's size is not + constant, or else return BITS_PER_WORD if the type actually turns out + to be an ERROR_MARK node. */ + +static inline unsigned HOST_WIDE_INT +simple_type_size_in_bits (type) + tree type; +{ + tree type_size_tree; + + if (TREE_CODE (type) == ERROR_MARK) + return BITS_PER_WORD; + type_size_tree = TYPE_SIZE (type); + + if (type_size_tree == NULL_TREE) + return 0; + if (! host_integerp (type_size_tree, 1)) + return TYPE_ALIGN (type); + return tree_low_cst (type_size_tree, 1); +} + +/* Given a pointer to what is assumed to be a FIELD_DECL node, compute and + return the byte offset of the lowest addressed byte of the "containing + object" for the given FIELD_DECL, or return 0 if we are unable to deter- + mine what that offset is, either because the argument turns out to be a + pointer to an ERROR_MARK node, or because the offset is actually variable. + (We can't handle the latter case just yet.) */ + +static HOST_WIDE_INT +field_byte_offset (decl) + tree decl; +{ + unsigned int type_align_in_bytes; + unsigned int type_align_in_bits; + unsigned HOST_WIDE_INT type_size_in_bits; + HOST_WIDE_INT object_offset_in_align_units; + HOST_WIDE_INT object_offset_in_bits; + HOST_WIDE_INT object_offset_in_bytes; + tree type; + tree field_size_tree; + HOST_WIDE_INT bitpos_int; + HOST_WIDE_INT deepest_bitpos; + unsigned HOST_WIDE_INT field_size_in_bits; + + if (TREE_CODE (decl) == ERROR_MARK) + return 0; + + if (TREE_CODE (decl) != FIELD_DECL) + abort (); + + type = field_type (decl); + field_size_tree = DECL_SIZE (decl); + + /* The size could be unspecified if there was an error, or for + a flexible array member. */ + if (! field_size_tree) + field_size_tree = bitsize_zero_node; + + /* We cannot yet cope with fields whose positions or sizes are variable, + so for now, when we see such things, we simply return 0. Someday, + we may be able to handle such cases, but it will be damn difficult. */ + + if (! host_integerp (bit_position (decl), 0) + || ! host_integerp (field_size_tree, 1)) + return 0; + + bitpos_int = int_bit_position (decl); + field_size_in_bits = tree_low_cst (field_size_tree, 1); + + type_size_in_bits = simple_type_size_in_bits (type); + type_align_in_bits = simple_type_align_in_bits (type); + type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT; + + /* Note that the GCC front-end doesn't make any attempt to keep track + of the starting bit offset (relative to the start of the containing + structure type) of the hypothetical "containing object" for a bit- + field. Thus, when computing the byte offset value for the start of + the "containing object" of a bit-field, we must deduce this infor- + mation on our own. + + This can be rather tricky to do in some cases. For example, handling + the following structure type definition when compiling for an i386/i486 + target (which only aligns long long's to 32-bit boundaries) can be very + tricky: + + struct S { + int field1; + long long field2:31; + }; + + Fortunately, there is a simple rule-of-thumb which can be used in such + cases. When compiling for an i386/i486, GCC will allocate 8 bytes for + the structure shown above. It decides to do this based upon one simple + rule for bit-field allocation. Quite simply, GCC allocates each "con- + taining object" for each bit-field at the first (i.e. lowest addressed) + legitimate alignment boundary (based upon the required minimum alignment + for the declared type of the field) which it can possibly use, subject + to the condition that there is still enough available space remaining + in the containing object (when allocated at the selected point) to + fully accommodate all of the bits of the bit-field itself. + + This simple rule makes it obvious why GCC allocates 8 bytes for each + object of the structure type shown above. When looking for a place to + allocate the "containing object" for `field2', the compiler simply tries + to allocate a 64-bit "containing object" at each successive 32-bit + boundary (starting at zero) until it finds a place to allocate that 64- + bit field such that at least 31 contiguous (and previously unallocated) + bits remain within that selected 64 bit field. (As it turns out, for + the example above, the compiler finds that it is OK to allocate the + "containing object" 64-bit field at bit-offset zero within the + structure type.) + + Here we attempt to work backwards from the limited set of facts we're + given, and we try to deduce from those facts, where GCC must have + believed that the containing object started (within the structure type). + + The value we deduce is then used (by the callers of this routine) to + generate AT_location and AT_bit_offset attributes for fields (both + bit-fields and, in the case of AT_location, regular fields as well). */ + + /* Figure out the bit-distance from the start of the structure to the + "deepest" bit of the bit-field. */ + deepest_bitpos = bitpos_int + field_size_in_bits; + + /* This is the tricky part. Use some fancy footwork to deduce where the + lowest addressed bit of the containing object must be. */ + object_offset_in_bits + = ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits; + + /* Compute the offset of the containing object in "alignment units". */ + object_offset_in_align_units = object_offset_in_bits / type_align_in_bits; + + /* Compute the offset of the containing object in bytes. */ + object_offset_in_bytes = object_offset_in_align_units * type_align_in_bytes; + + /* The above code assumes that the field does not cross an alignment + boundary. This can happen if PCC_BITFIELD_TYPE_MATTERS is not defined, + or if the structure is packed. If this happens, then we get an object + which starts after the bitfield, which means that the bit offset is + negative. Gdb fails when given negative bit offsets. We avoid this + by recomputing using the first bit of the bitfield. This will give + us an object which does not completely contain the bitfield, but it + will be aligned, and it will contain the first bit of the bitfield. + + However, only do this for a BYTES_BIG_ENDIAN target. For a + ! BYTES_BIG_ENDIAN target, bitpos_int + field_size_in_bits is the first + first bit of the bitfield. If we recompute using bitpos_int + 1 below, + then we end up computing the object byte offset for the wrong word of the + desired bitfield, which in turn causes the field offset to be negative + in bit_offset_attribute. */ + if (BYTES_BIG_ENDIAN + && object_offset_in_bits > bitpos_int) + { + deepest_bitpos = bitpos_int + 1; + object_offset_in_bits + = ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits; + object_offset_in_align_units = (object_offset_in_bits + / type_align_in_bits); + object_offset_in_bytes = (object_offset_in_align_units + * type_align_in_bytes); + } + + return object_offset_in_bytes; +} + +/****************************** attributes *********************************/ + +/* The following routines are responsible for writing out the various types + of Dwarf attributes (and any following data bytes associated with them). + These routines are listed in order based on the numerical codes of their + associated attributes. */ + +/* Generate an AT_sibling attribute. */ + +static inline void +sibling_attribute () +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_sibling); + sprintf (label, DIE_BEGIN_LABEL_FMT, NEXT_DIE_NUM); + ASM_OUTPUT_DWARF_REF (asm_out_file, label); +} + +/* Output the form of location attributes suitable for whole variables and + whole parameters. Note that the location attributes for struct fields + are generated by the routine `data_member_location_attribute' below. */ + +static void +location_attribute (rtl) + rtx rtl; +{ + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_location); + sprintf (begin_label, LOC_BEGIN_LABEL_FMT, current_dienum); + sprintf (end_label, LOC_END_LABEL_FMT, current_dienum); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label); + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + + /* Handle a special case. If we are about to output a location descriptor + for a variable or parameter which has been optimized out of existence, + don't do that. Instead we output a zero-length location descriptor + value as part of the location attribute. + + A variable which has been optimized out of existence will have a + DECL_RTL value which denotes a pseudo-reg. + + Currently, in some rare cases, variables can have DECL_RTL values + which look like (MEM (REG pseudo-reg#)). These cases are due to + bugs elsewhere in the compiler. We treat such cases + as if the variable(s) in question had been optimized out of existence. + + Note that in all cases where we wish to express the fact that a + variable has been optimized out of existence, we do not simply + suppress the generation of the entire location attribute because + the absence of a location attribute in certain kinds of DIEs is + used to indicate something else entirely... i.e. that the DIE + represents an object declaration, but not a definition. So saith + the PLSIG. + */ + + if (! is_pseudo_reg (rtl) + && (GET_CODE (rtl) != MEM || ! is_pseudo_reg (XEXP (rtl, 0)))) + output_loc_descriptor (rtl); + + ASM_OUTPUT_LABEL (asm_out_file, end_label); +} + +/* Output the specialized form of location attribute used for data members + of struct and union types. + + In the special case of a FIELD_DECL node which represents a bit-field, + the "offset" part of this special location descriptor must indicate the + distance in bytes from the lowest-addressed byte of the containing + struct or union type to the lowest-addressed byte of the "containing + object" for the bit-field. (See the `field_byte_offset' function above.) + + For any given bit-field, the "containing object" is a hypothetical + object (of some integral or enum type) within which the given bit-field + lives. The type of this hypothetical "containing object" is always the + same as the declared type of the individual bit-field itself (for GCC + anyway... the DWARF spec doesn't actually mandate this). + + Note that it is the size (in bytes) of the hypothetical "containing + object" which will be given in the AT_byte_size attribute for this + bit-field. (See the `byte_size_attribute' function below.) It is + also used when calculating the value of the AT_bit_offset attribute. + (See the `bit_offset_attribute' function below.) */ + +static void +data_member_location_attribute (t) + tree t; +{ + unsigned object_offset_in_bytes; + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (TREE_CODE (t) == TREE_VEC) + object_offset_in_bytes = tree_low_cst (BINFO_OFFSET (t), 0); + else + object_offset_in_bytes = field_byte_offset (t); + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_location); + sprintf (begin_label, LOC_BEGIN_LABEL_FMT, current_dienum); + sprintf (end_label, LOC_END_LABEL_FMT, current_dienum); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label); + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_CONST); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, object_offset_in_bytes); + ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_ADD); + ASM_OUTPUT_LABEL (asm_out_file, end_label); +} + +/* Output an AT_const_value attribute for a variable or a parameter which + does not have a "location" either in memory or in a register. These + things can arise in GNU C when a constant is passed as an actual + parameter to an inlined function. They can also arise in C++ where + declared constants do not necessarily get memory "homes". */ + +static void +const_value_attribute (rtl) + rtx rtl; +{ + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_const_value_block4); + sprintf (begin_label, LOC_BEGIN_LABEL_FMT, current_dienum); + sprintf (end_label, LOC_END_LABEL_FMT, current_dienum); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, end_label, begin_label); + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + + switch (GET_CODE (rtl)) + { + case CONST_INT: + /* Note that a CONST_INT rtx could represent either an integer or + a floating-point constant. A CONST_INT is used whenever the + constant will fit into a single word. In all such cases, the + original mode of the constant value is wiped out, and the + CONST_INT rtx is assigned VOIDmode. Since we no longer have + precise mode information for these constants, we always just + output them using 4 bytes. */ + + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, (unsigned) INTVAL (rtl)); + break; + + case CONST_DOUBLE: + /* Note that a CONST_DOUBLE rtx could represent either an integer + or a floating-point constant. A CONST_DOUBLE is used whenever + the constant requires more than one word in order to be adequately + represented. In all such cases, the original mode of the constant + value is preserved as the mode of the CONST_DOUBLE rtx, but for + simplicity we always just output CONST_DOUBLEs using 8 bytes. */ + + ASM_OUTPUT_DWARF_DATA8 (asm_out_file, + (unsigned int) CONST_DOUBLE_HIGH (rtl), + (unsigned int) CONST_DOUBLE_LOW (rtl)); + break; + + case CONST_STRING: + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, XSTR (rtl, 0)); + break; + + case SYMBOL_REF: + case LABEL_REF: + case CONST: + ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, rtl); + break; + + case PLUS: + /* In cases where an inlined instance of an inline function is passed + the address of an `auto' variable (which is local to the caller) + we can get a situation where the DECL_RTL of the artificial + local variable (for the inlining) which acts as a stand-in for + the corresponding formal parameter (of the inline function) + will look like (plus:SI (reg:SI FRAME_PTR) (const_int ...)). + This is not exactly a compile-time constant expression, but it + isn't the address of the (artificial) local variable either. + Rather, it represents the *value* which the artificial local + variable always has during its lifetime. We currently have no + way to represent such quasi-constant values in Dwarf, so for now + we just punt and generate an AT_const_value attribute with form + FORM_BLOCK4 and a length of zero. */ + break; + + default: + abort (); /* No other kinds of rtx should be possible here. */ + } + + ASM_OUTPUT_LABEL (asm_out_file, end_label); +} + +/* Generate *either* an AT_location attribute or else an AT_const_value + data attribute for a variable or a parameter. We generate the + AT_const_value attribute only in those cases where the given + variable or parameter does not have a true "location" either in + memory or in a register. This can happen (for example) when a + constant is passed as an actual argument in a call to an inline + function. (It's possible that these things can crop up in other + ways also.) Note that one type of constant value which can be + passed into an inlined function is a constant pointer. This can + happen for example if an actual argument in an inlined function + call evaluates to a compile-time constant address. */ + +static void +location_or_const_value_attribute (decl) + tree decl; +{ + rtx rtl; + + if (TREE_CODE (decl) == ERROR_MARK) + return; + + if ((TREE_CODE (decl) != VAR_DECL) && (TREE_CODE (decl) != PARM_DECL)) + { + /* Should never happen. */ + abort (); + return; + } + + /* Here we have to decide where we are going to say the parameter "lives" + (as far as the debugger is concerned). We only have a couple of choices. + GCC provides us with DECL_RTL and with DECL_INCOMING_RTL. DECL_RTL + normally indicates where the parameter lives during most of the activa- + tion of the function. If optimization is enabled however, this could + be either NULL or else a pseudo-reg. Both of those cases indicate that + the parameter doesn't really live anywhere (as far as the code generation + parts of GCC are concerned) during most of the function's activation. + That will happen (for example) if the parameter is never referenced + within the function. + + We could just generate a location descriptor here for all non-NULL + non-pseudo values of DECL_RTL and ignore all of the rest, but we can + be a little nicer than that if we also consider DECL_INCOMING_RTL in + cases where DECL_RTL is NULL or is a pseudo-reg. + + Note however that we can only get away with using DECL_INCOMING_RTL as + a backup substitute for DECL_RTL in certain limited cases. In cases + where DECL_ARG_TYPE(decl) indicates the same type as TREE_TYPE(decl) + we can be sure that the parameter was passed using the same type as it + is declared to have within the function, and that its DECL_INCOMING_RTL + points us to a place where a value of that type is passed. In cases + where DECL_ARG_TYPE(decl) and TREE_TYPE(decl) are different types + however, we cannot (in general) use DECL_INCOMING_RTL as a backup + substitute for DECL_RTL because in these cases, DECL_INCOMING_RTL + points us to a value of some type which is *different* from the type + of the parameter itself. Thus, if we tried to use DECL_INCOMING_RTL + to generate a location attribute in such cases, the debugger would + end up (for example) trying to fetch a `float' from a place which + actually contains the first part of a `double'. That would lead to + really incorrect and confusing output at debug-time, and we don't + want that now do we? + + So in general, we DO NOT use DECL_INCOMING_RTL as a backup for DECL_RTL + in cases where DECL_ARG_TYPE(decl) != TREE_TYPE(decl). There are a + couple of cute exceptions however. On little-endian machines we can + get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE(decl) is + not the same as TREE_TYPE(decl) but only when DECL_ARG_TYPE(decl) is + an integral type which is smaller than TREE_TYPE(decl). These cases + arise when (on a little-endian machine) a non-prototyped function has + a parameter declared to be of type `short' or `char'. In such cases, + TREE_TYPE(decl) will be `short' or `char', DECL_ARG_TYPE(decl) will be + `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the + passed `int' value. If the debugger then uses that address to fetch a + `short' or a `char' (on a little-endian machine) the result will be the + correct data, so we allow for such exceptional cases below. + + Note that our goal here is to describe the place where the given formal + parameter lives during most of the function's activation (i.e. between + the end of the prologue and the start of the epilogue). We'll do that + as best as we can. Note however that if the given formal parameter is + modified sometime during the execution of the function, then a stack + backtrace (at debug-time) will show the function as having been called + with the *new* value rather than the value which was originally passed + in. This happens rarely enough that it is not a major problem, but it + *is* a problem, and I'd like to fix it. A future version of dwarfout.c + may generate two additional attributes for any given TAG_formal_parameter + DIE which will describe the "passed type" and the "passed location" for + the given formal parameter in addition to the attributes we now generate + to indicate the "declared type" and the "active location" for each + parameter. This additional set of attributes could be used by debuggers + for stack backtraces. + + Separately, note that sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL + can be NULL also. This happens (for example) for inlined-instances of + inline function formal parameters which are never referenced. This really + shouldn't be happening. All PARM_DECL nodes should get valid non-NULL + DECL_INCOMING_RTL values, but integrate.c doesn't currently generate + these values for inlined instances of inline function parameters, so + when we see such cases, we are just out-of-luck for the time + being (until integrate.c gets fixed). + */ + + /* Use DECL_RTL as the "location" unless we find something better. */ + rtl = DECL_RTL (decl); + + if (TREE_CODE (decl) == PARM_DECL) + if (rtl == NULL_RTX || is_pseudo_reg (rtl)) + { + /* This decl represents a formal parameter which was optimized out. */ + tree declared_type = type_main_variant (TREE_TYPE (decl)); + tree passed_type = type_main_variant (DECL_ARG_TYPE (decl)); + + /* Note that DECL_INCOMING_RTL may be NULL in here, but we handle + *all* cases where (rtl == NULL_RTX) just below. */ + + if (declared_type == passed_type) + rtl = DECL_INCOMING_RTL (decl); + else if (! BYTES_BIG_ENDIAN) + if (TREE_CODE (declared_type) == INTEGER_TYPE) + /* NMS WTF? */ + if (TYPE_SIZE (declared_type) <= TYPE_SIZE (passed_type)) + rtl = DECL_INCOMING_RTL (decl); + } + + if (rtl == NULL_RTX) + return; + + rtl = eliminate_regs (rtl, 0, NULL_RTX); +#ifdef LEAF_REG_REMAP + if (current_function_uses_only_leaf_regs) + leaf_renumber_regs_insn (rtl); +#endif + + switch (GET_CODE (rtl)) + { + case ADDRESSOF: + /* The address of a variable that was optimized away; don't emit + anything. */ + break; + + case CONST_INT: + case CONST_DOUBLE: + case CONST_STRING: + case SYMBOL_REF: + case LABEL_REF: + case CONST: + case PLUS: /* DECL_RTL could be (plus (reg ...) (const_int ...)) */ + const_value_attribute (rtl); + break; + + case MEM: + case REG: + case SUBREG: + location_attribute (rtl); + break; + + case CONCAT: + /* ??? CONCAT is used for complex variables, which may have the real + part stored in one place and the imag part stored somewhere else. + DWARF1 has no way to describe a variable that lives in two different + places, so we just describe where the first part lives, and hope that + the second part is stored after it. */ + location_attribute (XEXP (rtl, 0)); + break; + + default: + abort (); /* Should never happen. */ + } +} + +/* Generate an AT_name attribute given some string value to be included as + the value of the attribute. */ + +static inline void +name_attribute (name_string) + const char *name_string; +{ + if (name_string && *name_string) + { + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_name); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, name_string); + } +} + +static inline void +fund_type_attribute (ft_code) + unsigned ft_code; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_fund_type); + ASM_OUTPUT_DWARF_FUND_TYPE (asm_out_file, ft_code); +} + +static void +mod_fund_type_attribute (type, decl_const, decl_volatile) + tree type; + int decl_const; + int decl_volatile; +{ + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_mod_fund_type); + sprintf (begin_label, MT_BEGIN_LABEL_FMT, current_dienum); + sprintf (end_label, MT_END_LABEL_FMT, current_dienum); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label); + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + write_modifier_bytes (type, decl_const, decl_volatile); + ASM_OUTPUT_DWARF_FUND_TYPE (asm_out_file, + fundamental_type_code (root_type (type))); + ASM_OUTPUT_LABEL (asm_out_file, end_label); +} + +static inline void +user_def_type_attribute (type) + tree type; +{ + char ud_type_name[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_user_def_type); + sprintf (ud_type_name, TYPE_NAME_FMT, TYPE_UID (type)); + ASM_OUTPUT_DWARF_REF (asm_out_file, ud_type_name); +} + +static void +mod_u_d_type_attribute (type, decl_const, decl_volatile) + tree type; + int decl_const; + int decl_volatile; +{ + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char ud_type_name[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_mod_u_d_type); + sprintf (begin_label, MT_BEGIN_LABEL_FMT, current_dienum); + sprintf (end_label, MT_END_LABEL_FMT, current_dienum); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label); + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + write_modifier_bytes (type, decl_const, decl_volatile); + sprintf (ud_type_name, TYPE_NAME_FMT, TYPE_UID (root_type (type))); + ASM_OUTPUT_DWARF_REF (asm_out_file, ud_type_name); + ASM_OUTPUT_LABEL (asm_out_file, end_label); +} + +#ifdef USE_ORDERING_ATTRIBUTE +static inline void +ordering_attribute (ordering) + unsigned ordering; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_ordering); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, ordering); +} +#endif /* defined(USE_ORDERING_ATTRIBUTE) */ + +/* Note that the block of subscript information for an array type also + includes information about the element type of type given array type. */ + +static void +subscript_data_attribute (type) + tree type; +{ + unsigned dimension_number; + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_subscr_data); + sprintf (begin_label, SS_BEGIN_LABEL_FMT, current_dienum); + sprintf (end_label, SS_END_LABEL_FMT, current_dienum); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label); + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + + /* The GNU compilers represent multidimensional array types as sequences + of one dimensional array types whose element types are themselves array + types. Here we squish that down, so that each multidimensional array + type gets only one array_type DIE in the Dwarf debugging info. The + draft Dwarf specification say that we are allowed to do this kind + of compression in C (because there is no difference between an + array or arrays and a multidimensional array in C) but for other + source languages (e.g. Ada) we probably shouldn't do this. */ + + for (dimension_number = 0; + TREE_CODE (type) == ARRAY_TYPE; + type = TREE_TYPE (type), dimension_number++) + { + tree domain = TYPE_DOMAIN (type); + + /* Arrays come in three flavors. Unspecified bounds, fixed + bounds, and (in GNU C only) variable bounds. Handle all + three forms here. */ + + if (domain) + { + /* We have an array type with specified bounds. */ + + tree lower = TYPE_MIN_VALUE (domain); + tree upper = TYPE_MAX_VALUE (domain); + + /* Handle only fundamental types as index types for now. */ + if (! type_is_fundamental (domain)) + abort (); + + /* Output the representation format byte for this dimension. */ + ASM_OUTPUT_DWARF_FMT_BYTE (asm_out_file, + FMT_CODE (1, TREE_CODE (lower) == INTEGER_CST, + upper && TREE_CODE (upper) == INTEGER_CST)); + + /* Output the index type for this dimension. */ + ASM_OUTPUT_DWARF_FUND_TYPE (asm_out_file, + fundamental_type_code (domain)); + + /* Output the representation for the lower bound. */ + output_bound_representation (lower, dimension_number, 'l'); + + /* Output the representation for the upper bound. */ + if (upper) + output_bound_representation (upper, dimension_number, 'u'); + else + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, 0); + } + else + { + /* We have an array type with an unspecified length. For C and + C++ we can assume that this really means that (a) the index + type is an integral type, and (b) the lower bound is zero. + Note that Dwarf defines the representation of an unspecified + (upper) bound as being a zero-length location description. */ + + /* Output the array-bounds format byte. */ + + ASM_OUTPUT_DWARF_FMT_BYTE (asm_out_file, FMT_FT_C_X); + + /* Output the (assumed) index type. */ + + ASM_OUTPUT_DWARF_FUND_TYPE (asm_out_file, FT_integer); + + /* Output the (assumed) lower bound (constant) value. */ + + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); + + /* Output the (empty) location description for the upper bound. */ + + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, 0); + } + } + + /* Output the prefix byte that says that the element type is coming up. */ + + ASM_OUTPUT_DWARF_FMT_BYTE (asm_out_file, FMT_ET); + + /* Output a representation of the type of the elements of this array type. */ + + type_attribute (type, 0, 0); + + ASM_OUTPUT_LABEL (asm_out_file, end_label); +} + +static void +byte_size_attribute (tree_node) + tree tree_node; +{ + unsigned size; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_byte_size); + switch (TREE_CODE (tree_node)) + { + case ERROR_MARK: + size = 0; + break; + + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + case ARRAY_TYPE: + size = int_size_in_bytes (tree_node); + break; + + case FIELD_DECL: + /* For a data member of a struct or union, the AT_byte_size is + generally given as the number of bytes normally allocated for + an object of the *declared* type of the member itself. This + is true even for bit-fields. */ + size = simple_type_size_in_bits (field_type (tree_node)) + / BITS_PER_UNIT; + break; + + default: + abort (); + } + + /* Note that `size' might be -1 when we get to this point. If it + is, that indicates that the byte size of the entity in question + is variable. We have no good way of expressing this fact in Dwarf + at the present time, so just let the -1 pass on through. */ + + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, size); +} + +/* For a FIELD_DECL node which represents a bit-field, output an attribute + which specifies the distance in bits from the highest order bit of the + "containing object" for the bit-field to the highest order bit of the + bit-field itself. + + For any given bit-field, the "containing object" is a hypothetical + object (of some integral or enum type) within which the given bit-field + lives. The type of this hypothetical "containing object" is always the + same as the declared type of the individual bit-field itself. + + The determination of the exact location of the "containing object" for + a bit-field is rather complicated. It's handled by the `field_byte_offset' + function (above). + + Note that it is the size (in bytes) of the hypothetical "containing + object" which will be given in the AT_byte_size attribute for this + bit-field. (See `byte_size_attribute' above.) */ + +static inline void +bit_offset_attribute (decl) + tree decl; +{ + HOST_WIDE_INT object_offset_in_bytes = field_byte_offset (decl); + tree type = DECL_BIT_FIELD_TYPE (decl); + HOST_WIDE_INT bitpos_int; + HOST_WIDE_INT highest_order_object_bit_offset; + HOST_WIDE_INT highest_order_field_bit_offset; + HOST_WIDE_INT bit_offset; + + /* Must be a bit field. */ + if (!type + || TREE_CODE (decl) != FIELD_DECL) + abort (); + + /* We can't yet handle bit-fields whose offsets or sizes are variable, so + if we encounter such things, just return without generating any + attribute whatsoever. */ + + if (! host_integerp (bit_position (decl), 0) + || ! host_integerp (DECL_SIZE (decl), 1)) + return; + + bitpos_int = int_bit_position (decl); + + /* Note that the bit offset is always the distance (in bits) from the + highest-order bit of the "containing object" to the highest-order + bit of the bit-field itself. Since the "high-order end" of any + object or field is different on big-endian and little-endian machines, + the computation below must take account of these differences. */ + + highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT; + highest_order_field_bit_offset = bitpos_int; + + if (! BYTES_BIG_ENDIAN) + { + highest_order_field_bit_offset += tree_low_cst (DECL_SIZE (decl), 1); + highest_order_object_bit_offset += simple_type_size_in_bits (type); + } + + bit_offset = + (! BYTES_BIG_ENDIAN + ? highest_order_object_bit_offset - highest_order_field_bit_offset + : highest_order_field_bit_offset - highest_order_object_bit_offset); + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_bit_offset); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, bit_offset); +} + +/* For a FIELD_DECL node which represents a bit field, output an attribute + which specifies the length in bits of the given field. */ + +static inline void +bit_size_attribute (decl) + tree decl; +{ + /* Must be a field and a bit field. */ + if (TREE_CODE (decl) != FIELD_DECL + || ! DECL_BIT_FIELD_TYPE (decl)) + abort (); + + if (host_integerp (DECL_SIZE (decl), 1)) + { + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_bit_size); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, + tree_low_cst (DECL_SIZE (decl), 1)); + } +} + +/* The following routine outputs the `element_list' attribute for enumeration + type DIEs. The element_lits attribute includes the names and values of + all of the enumeration constants associated with the given enumeration + type. */ + +static inline void +element_list_attribute (element) + tree element; +{ + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_element_list); + sprintf (begin_label, EE_BEGIN_LABEL_FMT, current_dienum); + sprintf (end_label, EE_END_LABEL_FMT, current_dienum); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, end_label, begin_label); + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + + /* Here we output a list of value/name pairs for each enumeration constant + defined for this enumeration type (as required), but we do it in REVERSE + order. The order is the one required by the draft #5 Dwarf specification + published by the UI/PLSIG. */ + + output_enumeral_list (element); /* Recursively output the whole list. */ + + ASM_OUTPUT_LABEL (asm_out_file, end_label); +} + +/* Generate an AT_stmt_list attribute. These are normally present only in + DIEs with a TAG_compile_unit tag. */ + +static inline void +stmt_list_attribute (label) + const char *label; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_stmt_list); + /* Don't use ASM_OUTPUT_DWARF_DATA4 here. */ + ASM_OUTPUT_DWARF_ADDR (asm_out_file, label); +} + +/* Generate an AT_low_pc attribute for a label DIE, a lexical_block DIE or + for a subroutine DIE. */ + +static inline void +low_pc_attribute (asm_low_label) + const char *asm_low_label; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_low_pc); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, asm_low_label); +} + +/* Generate an AT_high_pc attribute for a lexical_block DIE or for a + subroutine DIE. */ + +static inline void +high_pc_attribute (asm_high_label) + const char *asm_high_label; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_high_pc); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, asm_high_label); +} + +/* Generate an AT_body_begin attribute for a subroutine DIE. */ + +static inline void +body_begin_attribute (asm_begin_label) + const char *asm_begin_label; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_body_begin); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, asm_begin_label); +} + +/* Generate an AT_body_end attribute for a subroutine DIE. */ + +static inline void +body_end_attribute (asm_end_label) + const char *asm_end_label; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_body_end); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, asm_end_label); +} + +/* Generate an AT_language attribute given a LANG value. These attributes + are used only within TAG_compile_unit DIEs. */ + +static inline void +language_attribute (language_code) + unsigned language_code; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_language); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, language_code); +} + +static inline void +member_attribute (context) + tree context; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + /* Generate this attribute only for members in C++. */ + + if (context != NULL && is_tagged_type (context)) + { + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_member); + sprintf (label, TYPE_NAME_FMT, TYPE_UID (context)); + ASM_OUTPUT_DWARF_REF (asm_out_file, label); + } +} + +#if 0 +#ifndef SL_BEGIN_LABEL_FMT +#define SL_BEGIN_LABEL_FMT "*.L_sl%u" +#endif +#ifndef SL_END_LABEL_FMT +#define SL_END_LABEL_FMT "*.L_sl%u_e" +#endif + +static inline void +string_length_attribute (upper_bound) + tree upper_bound; +{ + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_string_length); + sprintf (begin_label, SL_BEGIN_LABEL_FMT, current_dienum); + sprintf (end_label, SL_END_LABEL_FMT, current_dienum); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label); + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + output_bound_representation (upper_bound, 0, 'u'); + ASM_OUTPUT_LABEL (asm_out_file, end_label); +} +#endif + +static inline void +comp_dir_attribute (dirname) + const char *dirname; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_comp_dir); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, dirname); +} + +static inline void +sf_names_attribute (sf_names_start_label) + const char *sf_names_start_label; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_sf_names); + /* Don't use ASM_OUTPUT_DWARF_DATA4 here. */ + ASM_OUTPUT_DWARF_ADDR (asm_out_file, sf_names_start_label); +} + +static inline void +src_info_attribute (src_info_start_label) + const char *src_info_start_label; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_src_info); + /* Don't use ASM_OUTPUT_DWARF_DATA4 here. */ + ASM_OUTPUT_DWARF_ADDR (asm_out_file, src_info_start_label); +} + +static inline void +mac_info_attribute (mac_info_start_label) + const char *mac_info_start_label; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_mac_info); + /* Don't use ASM_OUTPUT_DWARF_DATA4 here. */ + ASM_OUTPUT_DWARF_ADDR (asm_out_file, mac_info_start_label); +} + +static inline void +prototyped_attribute (func_type) + tree func_type; +{ + if ((strcmp (lang_hooks.name, "GNU C") == 0) + && (TYPE_ARG_TYPES (func_type) != NULL)) + { + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_prototyped); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, ""); + } +} + +static inline void +producer_attribute (producer) + const char *producer; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_producer); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, producer); +} + +static inline void +inline_attribute (decl) + tree decl; +{ + if (DECL_INLINE (decl)) + { + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_inline); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, ""); + } +} + +static inline void +containing_type_attribute (containing_type) + tree containing_type; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_containing_type); + sprintf (label, TYPE_NAME_FMT, TYPE_UID (containing_type)); + ASM_OUTPUT_DWARF_REF (asm_out_file, label); +} + +static inline void +abstract_origin_attribute (origin) + tree origin; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_abstract_origin); + switch (TREE_CODE_CLASS (TREE_CODE (origin))) + { + case 'd': + sprintf (label, DECL_NAME_FMT, DECL_UID (origin)); + break; + + case 't': + sprintf (label, TYPE_NAME_FMT, TYPE_UID (origin)); + break; + + default: + abort (); /* Should never happen. */ + + } + ASM_OUTPUT_DWARF_REF (asm_out_file, label); +} + +#ifdef DWARF_DECL_COORDINATES +static inline void +src_coords_attribute (src_fileno, src_lineno) + unsigned src_fileno; + unsigned src_lineno; +{ + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_src_coords); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, src_fileno); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, src_lineno); +} +#endif /* defined(DWARF_DECL_COORDINATES) */ + +static inline void +pure_or_virtual_attribute (func_decl) + tree func_decl; +{ + if (DECL_VIRTUAL_P (func_decl)) + { +#if 0 /* DECL_ABSTRACT_VIRTUAL_P is C++-specific. */ + if (DECL_ABSTRACT_VIRTUAL_P (func_decl)) + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_pure_virtual); + else +#endif + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_virtual); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, ""); + } +} + +/************************* end of attributes *****************************/ + +/********************* utility routines for DIEs *************************/ + +/* Output an AT_name attribute and an AT_src_coords attribute for the + given decl, but only if it actually has a name. */ + +static void +name_and_src_coords_attributes (decl) + tree decl; +{ + tree decl_name = DECL_NAME (decl); + + if (decl_name && IDENTIFIER_POINTER (decl_name)) + { + name_attribute (IDENTIFIER_POINTER (decl_name)); +#ifdef DWARF_DECL_COORDINATES + { + register unsigned file_index; + + /* This is annoying, but we have to pop out of the .debug section + for a moment while we call `lookup_filename' because calling it + may cause a temporary switch into the .debug_sfnames section and + most svr4 assemblers are not smart enough to be able to nest + section switches to any depth greater than one. Note that we + also can't skirt this issue by delaying all output to the + .debug_sfnames section unit the end of compilation because that + would cause us to have inter-section forward references and + Fred Fish sez that m68k/svr4 assemblers botch those. */ + + ASM_OUTPUT_POP_SECTION (asm_out_file); + file_index = lookup_filename (DECL_SOURCE_FILE (decl)); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SECTION); + + src_coords_attribute (file_index, DECL_SOURCE_LINE (decl)); + } +#endif /* defined(DWARF_DECL_COORDINATES) */ + } +} + +/* Many forms of DIEs contain a "type description" part. The following + routine writes out these "type descriptor" parts. */ + +static void +type_attribute (type, decl_const, decl_volatile) + tree type; + int decl_const; + int decl_volatile; +{ + enum tree_code code = TREE_CODE (type); + int root_type_modified; + + if (code == ERROR_MARK) + return; + + /* Handle a special case. For functions whose return type is void, + we generate *no* type attribute. (Note that no object may have + type `void', so this only applies to function return types. */ + + if (code == VOID_TYPE) + return; + + /* If this is a subtype, find the underlying type. Eventually, + this should write out the appropriate subtype info. */ + while ((code == INTEGER_TYPE || code == REAL_TYPE) + && TREE_TYPE (type) != 0) + type = TREE_TYPE (type), code = TREE_CODE (type); + + root_type_modified = (code == POINTER_TYPE || code == REFERENCE_TYPE + || decl_const || decl_volatile + || TYPE_READONLY (type) || TYPE_VOLATILE (type)); + + if (type_is_fundamental (root_type (type))) + { + if (root_type_modified) + mod_fund_type_attribute (type, decl_const, decl_volatile); + else + fund_type_attribute (fundamental_type_code (type)); + } + else + { + if (root_type_modified) + mod_u_d_type_attribute (type, decl_const, decl_volatile); + else + /* We have to get the type_main_variant here (and pass that to the + `user_def_type_attribute' routine) because the ..._TYPE node we + have might simply be a *copy* of some original type node (where + the copy was created to help us keep track of typedef names) + and that copy might have a different TYPE_UID from the original + ..._TYPE node. (Note that when `equate_type_number_to_die_number' + is labeling a given type DIE for future reference, it always and + only creates labels for DIEs representing *main variants*, and it + never even knows about non-main-variants.) */ + user_def_type_attribute (type_main_variant (type)); + } +} + +/* Given a tree pointer to a struct, class, union, or enum type node, return + a pointer to the (string) tag name for the given type, or zero if the + type was declared without a tag. */ + +static const char * +type_tag (type) + tree type; +{ + const char *name = 0; + + if (TYPE_NAME (type) != 0) + { + tree t = 0; + + /* Find the IDENTIFIER_NODE for the type name. */ + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + t = TYPE_NAME (type); + + /* The g++ front end makes the TYPE_NAME of *each* tagged type point to + a TYPE_DECL node, regardless of whether or not a `typedef' was + involved. */ + else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && ! DECL_IGNORED_P (TYPE_NAME (type))) + t = DECL_NAME (TYPE_NAME (type)); + + /* Now get the name as a string, or invent one. */ + if (t != 0) + name = IDENTIFIER_POINTER (t); + } + + return (name == 0 || *name == '\0') ? 0 : name; +} + +static inline void +dienum_push () +{ + /* Start by checking if the pending_sibling_stack needs to be expanded. + If necessary, expand it. */ + + if (pending_siblings == pending_siblings_allocated) + { + pending_siblings_allocated += PENDING_SIBLINGS_INCREMENT; + pending_sibling_stack + = (unsigned *) xrealloc (pending_sibling_stack, + pending_siblings_allocated * sizeof(unsigned)); + } + + pending_siblings++; + NEXT_DIE_NUM = next_unused_dienum++; +} + +/* Pop the sibling stack so that the most recently pushed DIEnum becomes the + NEXT_DIE_NUM. */ + +static inline void +dienum_pop () +{ + pending_siblings--; +} + +static inline tree +member_declared_type (member) + tree member; +{ + return (DECL_BIT_FIELD_TYPE (member)) + ? DECL_BIT_FIELD_TYPE (member) + : TREE_TYPE (member); +} + +/* Get the function's label, as described by its RTL. + This may be different from the DECL_NAME name used + in the source file. */ + +static const char * +function_start_label (decl) + tree decl; +{ + rtx x; + const char *fnname; + + x = DECL_RTL (decl); + if (GET_CODE (x) != MEM) + abort (); + x = XEXP (x, 0); + if (GET_CODE (x) != SYMBOL_REF) + abort (); + fnname = XSTR (x, 0); + return fnname; +} + + +/******************************* DIEs ************************************/ + +/* Output routines for individual types of DIEs. */ + +/* Note that every type of DIE (except a null DIE) gets a sibling. */ + +static void +output_array_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_array_type); + sibling_attribute (); + equate_type_number_to_die_number (type); + member_attribute (TYPE_CONTEXT (type)); + + /* I believe that we can default the array ordering. SDB will probably + do the right things even if AT_ordering is not present. It's not + even an issue until we start to get into multidimensional arrays + anyway. If SDB is ever caught doing the Wrong Thing for multi- + dimensional arrays, then we'll have to put the AT_ordering attribute + back in. (But if and when we find out that we need to put these in, + we will only do so for multidimensional arrays. After all, we don't + want to waste space in the .debug section now do we?) */ + +#ifdef USE_ORDERING_ATTRIBUTE + ordering_attribute (ORD_row_major); +#endif /* defined(USE_ORDERING_ATTRIBUTE) */ + + subscript_data_attribute (type); +} + +static void +output_set_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_set_type); + sibling_attribute (); + equate_type_number_to_die_number (type); + member_attribute (TYPE_CONTEXT (type)); + type_attribute (TREE_TYPE (type), 0, 0); +} + +#if 0 +/* Implement this when there is a GNU FORTRAN or GNU Ada front end. */ + +static void +output_entry_point_die (arg) + void *arg; +{ + tree decl = arg; + tree origin = decl_ultimate_origin (decl); + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_entry_point); + sibling_attribute (); + dienum_push (); + if (origin != NULL) + abstract_origin_attribute (origin); + else + { + name_and_src_coords_attributes (decl); + member_attribute (DECL_CONTEXT (decl)); + type_attribute (TREE_TYPE (TREE_TYPE (decl)), 0, 0); + } + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die_number (decl); + else + low_pc_attribute (function_start_label (decl)); +} +#endif + +/* Output a DIE to represent an inlined instance of an enumeration type. */ + +static void +output_inlined_enumeration_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_enumeration_type); + sibling_attribute (); + if (!TREE_ASM_WRITTEN (type)) + abort (); + abstract_origin_attribute (type); +} + +/* Output a DIE to represent an inlined instance of a structure type. */ + +static void +output_inlined_structure_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_structure_type); + sibling_attribute (); + if (!TREE_ASM_WRITTEN (type)) + abort (); + abstract_origin_attribute (type); +} + +/* Output a DIE to represent an inlined instance of a union type. */ + +static void +output_inlined_union_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_union_type); + sibling_attribute (); + if (!TREE_ASM_WRITTEN (type)) + abort (); + abstract_origin_attribute (type); +} + +/* Output a DIE to represent an enumeration type. Note that these DIEs + include all of the information about the enumeration values also. + This information is encoded into the element_list attribute. */ + +static void +output_enumeration_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_enumeration_type); + sibling_attribute (); + equate_type_number_to_die_number (type); + name_attribute (type_tag (type)); + member_attribute (TYPE_CONTEXT (type)); + + /* Handle a GNU C/C++ extension, i.e. incomplete enum types. If the + given enum type is incomplete, do not generate the AT_byte_size + attribute or the AT_element_list attribute. */ + + if (COMPLETE_TYPE_P (type)) + { + byte_size_attribute (type); + element_list_attribute (TYPE_FIELDS (type)); + } +} + +/* Output a DIE to represent either a real live formal parameter decl or + to represent just the type of some formal parameter position in some + function type. + + Note that this routine is a bit unusual because its argument may be + a ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which + represents an inlining of some PARM_DECL) or else some sort of a + ..._TYPE node. If it's the former then this function is being called + to output a DIE to represent a formal parameter object (or some inlining + thereof). If it's the latter, then this function is only being called + to output a TAG_formal_parameter DIE to stand as a placeholder for some + formal argument type of some subprogram type. */ + +static void +output_formal_parameter_die (arg) + void *arg; +{ + tree node = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_formal_parameter); + sibling_attribute (); + + switch (TREE_CODE_CLASS (TREE_CODE (node))) + { + case 'd': /* We were called with some kind of a ..._DECL node. */ + { + register tree origin = decl_ultimate_origin (node); + + if (origin != NULL) + abstract_origin_attribute (origin); + else + { + name_and_src_coords_attributes (node); + type_attribute (TREE_TYPE (node), + TREE_READONLY (node), TREE_THIS_VOLATILE (node)); + } + if (DECL_ABSTRACT (node)) + equate_decl_number_to_die_number (node); + else + location_or_const_value_attribute (node); + } + break; + + case 't': /* We were called with some kind of a ..._TYPE node. */ + type_attribute (node, 0, 0); + break; + + default: + abort (); /* Should never happen. */ + } +} + +/* Output a DIE to represent a declared function (either file-scope + or block-local) which has "external linkage" (according to ANSI-C). */ + +static void +output_global_subroutine_die (arg) + void *arg; +{ + tree decl = arg; + tree origin = decl_ultimate_origin (decl); + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_global_subroutine); + sibling_attribute (); + dienum_push (); + if (origin != NULL) + abstract_origin_attribute (origin); + else + { + tree type = TREE_TYPE (decl); + + name_and_src_coords_attributes (decl); + inline_attribute (decl); + prototyped_attribute (type); + member_attribute (DECL_CONTEXT (decl)); + type_attribute (TREE_TYPE (type), 0, 0); + pure_or_virtual_attribute (decl); + } + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die_number (decl); + else + { + if (! DECL_EXTERNAL (decl) && ! in_class + && decl == current_function_decl) + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + low_pc_attribute (function_start_label (decl)); + sprintf (label, FUNC_END_LABEL_FMT, current_function_funcdef_no); + high_pc_attribute (label); + if (use_gnu_debug_info_extensions) + { + sprintf (label, BODY_BEGIN_LABEL_FMT, + current_function_funcdef_no); + body_begin_attribute (label); + sprintf (label, BODY_END_LABEL_FMT, current_function_funcdef_no); + body_end_attribute (label); + } + } + } +} + +/* Output a DIE to represent a declared data object (either file-scope + or block-local) which has "external linkage" (according to ANSI-C). */ + +static void +output_global_variable_die (arg) + void *arg; +{ + tree decl = arg; + tree origin = decl_ultimate_origin (decl); + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_global_variable); + sibling_attribute (); + if (origin != NULL) + abstract_origin_attribute (origin); + else + { + name_and_src_coords_attributes (decl); + member_attribute (DECL_CONTEXT (decl)); + type_attribute (TREE_TYPE (decl), + TREE_READONLY (decl), TREE_THIS_VOLATILE (decl)); + } + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die_number (decl); + else + { + if (! DECL_EXTERNAL (decl) && ! in_class + && current_function_decl == decl_function_context (decl)) + location_or_const_value_attribute (decl); + } +} + +static void +output_label_die (arg) + void *arg; +{ + tree decl = arg; + tree origin = decl_ultimate_origin (decl); + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_label); + sibling_attribute (); + if (origin != NULL) + abstract_origin_attribute (origin); + else + name_and_src_coords_attributes (decl); + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die_number (decl); + else + { + rtx insn = DECL_RTL (decl); + + /* Deleted labels are programmer specified labels which have been + eliminated because of various optimisations. We still emit them + here so that it is possible to put breakpoints on them. */ + if (GET_CODE (insn) == CODE_LABEL + || ((GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL))) + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + /* When optimization is enabled (via -O) some parts of the compiler + (e.g. jump.c and cse.c) may try to delete CODE_LABEL insns which + represent source-level labels which were explicitly declared by + the user. This really shouldn't be happening though, so catch + it if it ever does happen. */ + + if (INSN_DELETED_P (insn)) + abort (); /* Should never happen. */ + + ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn)); + low_pc_attribute (label); + } + } +} + +static void +output_lexical_block_die (arg) + void *arg; +{ + tree stmt = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_lexical_block); + sibling_attribute (); + dienum_push (); + if (! BLOCK_ABSTRACT (stmt)) + { + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + sprintf (begin_label, BLOCK_BEGIN_LABEL_FMT, BLOCK_NUMBER (stmt)); + low_pc_attribute (begin_label); + sprintf (end_label, BLOCK_END_LABEL_FMT, BLOCK_NUMBER (stmt)); + high_pc_attribute (end_label); + } +} + +static void +output_inlined_subroutine_die (arg) + void *arg; +{ + tree stmt = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_inlined_subroutine); + sibling_attribute (); + dienum_push (); + abstract_origin_attribute (block_ultimate_origin (stmt)); + if (! BLOCK_ABSTRACT (stmt)) + { + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + sprintf (begin_label, BLOCK_BEGIN_LABEL_FMT, BLOCK_NUMBER (stmt)); + low_pc_attribute (begin_label); + sprintf (end_label, BLOCK_END_LABEL_FMT, BLOCK_NUMBER (stmt)); + high_pc_attribute (end_label); + } +} + +/* Output a DIE to represent a declared data object (either file-scope + or block-local) which has "internal linkage" (according to ANSI-C). */ + +static void +output_local_variable_die (arg) + void *arg; +{ + tree decl = arg; + tree origin = decl_ultimate_origin (decl); + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_local_variable); + sibling_attribute (); + if (origin != NULL) + abstract_origin_attribute (origin); + else + { + name_and_src_coords_attributes (decl); + member_attribute (DECL_CONTEXT (decl)); + type_attribute (TREE_TYPE (decl), + TREE_READONLY (decl), TREE_THIS_VOLATILE (decl)); + } + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die_number (decl); + else + location_or_const_value_attribute (decl); +} + +static void +output_member_die (arg) + void *arg; +{ + tree decl = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_member); + sibling_attribute (); + name_and_src_coords_attributes (decl); + member_attribute (DECL_CONTEXT (decl)); + type_attribute (member_declared_type (decl), + TREE_READONLY (decl), TREE_THIS_VOLATILE (decl)); + if (DECL_BIT_FIELD_TYPE (decl)) /* If this is a bit field... */ + { + byte_size_attribute (decl); + bit_size_attribute (decl); + bit_offset_attribute (decl); + } + data_member_location_attribute (decl); +} + +#if 0 +/* Don't generate either pointer_type DIEs or reference_type DIEs. Use + modified types instead. + + We keep this code here just in case these types of DIEs may be + needed to represent certain things in other languages (e.g. Pascal) + someday. */ + +static void +output_pointer_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_pointer_type); + sibling_attribute (); + equate_type_number_to_die_number (type); + member_attribute (TYPE_CONTEXT (type)); + type_attribute (TREE_TYPE (type), 0, 0); +} + +static void +output_reference_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_reference_type); + sibling_attribute (); + equate_type_number_to_die_number (type); + member_attribute (TYPE_CONTEXT (type)); + type_attribute (TREE_TYPE (type), 0, 0); +} +#endif + +static void +output_ptr_to_mbr_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_ptr_to_member_type); + sibling_attribute (); + equate_type_number_to_die_number (type); + member_attribute (TYPE_CONTEXT (type)); + containing_type_attribute (TYPE_OFFSET_BASETYPE (type)); + type_attribute (TREE_TYPE (type), 0, 0); +} + +static void +output_compile_unit_die (arg) + void *arg; +{ + const char *main_input_filename = arg; + const char *language_string = lang_hooks.name; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_compile_unit); + sibling_attribute (); + dienum_push (); + name_attribute (main_input_filename); + + { + char producer[250]; + + sprintf (producer, "%s %s", language_string, version_string); + producer_attribute (producer); + } + + if (strcmp (language_string, "GNU C++") == 0) + language_attribute (LANG_C_PLUS_PLUS); + else if (strcmp (language_string, "GNU Ada") == 0) + language_attribute (LANG_ADA83); + else if (strcmp (language_string, "GNU F77") == 0) + language_attribute (LANG_FORTRAN77); + else if (strcmp (language_string, "GNU Pascal") == 0) + language_attribute (LANG_PASCAL83); + else if (strcmp (language_string, "GNU Java") == 0) + language_attribute (LANG_JAVA); + else + language_attribute (LANG_C89); + low_pc_attribute (TEXT_BEGIN_LABEL); + high_pc_attribute (TEXT_END_LABEL); + if (debug_info_level >= DINFO_LEVEL_NORMAL) + stmt_list_attribute (LINE_BEGIN_LABEL); + + { + const char *wd = getpwd (); + if (wd) + comp_dir_attribute (wd); + } + + if (debug_info_level >= DINFO_LEVEL_NORMAL && use_gnu_debug_info_extensions) + { + sf_names_attribute (SFNAMES_BEGIN_LABEL); + src_info_attribute (SRCINFO_BEGIN_LABEL); + if (debug_info_level >= DINFO_LEVEL_VERBOSE) + mac_info_attribute (MACINFO_BEGIN_LABEL); + } +} + +static void +output_string_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_string_type); + sibling_attribute (); + equate_type_number_to_die_number (type); + member_attribute (TYPE_CONTEXT (type)); + /* this is a fixed length string */ + byte_size_attribute (type); +} + +static void +output_inheritance_die (arg) + void *arg; +{ + tree binfo = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_inheritance); + sibling_attribute (); + type_attribute (BINFO_TYPE (binfo), 0, 0); + data_member_location_attribute (binfo); + if (TREE_VIA_VIRTUAL (binfo)) + { + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_virtual); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, ""); + } + if (TREE_VIA_PUBLIC (binfo)) + { + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_public); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, ""); + } + else if (TREE_VIA_PROTECTED (binfo)) + { + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_protected); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, ""); + } +} + +static void +output_structure_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_structure_type); + sibling_attribute (); + equate_type_number_to_die_number (type); + name_attribute (type_tag (type)); + member_attribute (TYPE_CONTEXT (type)); + + /* If this type has been completed, then give it a byte_size attribute + and prepare to give a list of members. Otherwise, don't do either of + these things. In the latter case, we will not be generating a list + of members (since we don't have any idea what they might be for an + incomplete type). */ + + if (COMPLETE_TYPE_P (type)) + { + dienum_push (); + byte_size_attribute (type); + } +} + +/* Output a DIE to represent a declared function (either file-scope + or block-local) which has "internal linkage" (according to ANSI-C). */ + +static void +output_local_subroutine_die (arg) + void *arg; +{ + tree decl = arg; + tree origin = decl_ultimate_origin (decl); + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_subroutine); + sibling_attribute (); + dienum_push (); + if (origin != NULL) + abstract_origin_attribute (origin); + else + { + tree type = TREE_TYPE (decl); + + name_and_src_coords_attributes (decl); + inline_attribute (decl); + prototyped_attribute (type); + member_attribute (DECL_CONTEXT (decl)); + type_attribute (TREE_TYPE (type), 0, 0); + pure_or_virtual_attribute (decl); + } + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die_number (decl); + else + { + /* Avoid getting screwed up in cases where a function was declared + static but where no definition was ever given for it. */ + + if (TREE_ASM_WRITTEN (decl)) + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + low_pc_attribute (function_start_label (decl)); + sprintf (label, FUNC_END_LABEL_FMT, current_function_funcdef_no); + high_pc_attribute (label); + if (use_gnu_debug_info_extensions) + { + sprintf (label, BODY_BEGIN_LABEL_FMT, + current_function_funcdef_no); + body_begin_attribute (label); + sprintf (label, BODY_END_LABEL_FMT, current_function_funcdef_no); + body_end_attribute (label); + } + } + } +} + +static void +output_subroutine_type_die (arg) + void *arg; +{ + tree type = arg; + tree return_type = TREE_TYPE (type); + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_subroutine_type); + sibling_attribute (); + dienum_push (); + equate_type_number_to_die_number (type); + prototyped_attribute (type); + member_attribute (TYPE_CONTEXT (type)); + type_attribute (return_type, 0, 0); +} + +static void +output_typedef_die (arg) + void *arg; +{ + tree decl = arg; + tree origin = decl_ultimate_origin (decl); + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_typedef); + sibling_attribute (); + if (origin != NULL) + abstract_origin_attribute (origin); + else + { + name_and_src_coords_attributes (decl); + member_attribute (DECL_CONTEXT (decl)); + type_attribute (TREE_TYPE (decl), + TREE_READONLY (decl), TREE_THIS_VOLATILE (decl)); + } + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die_number (decl); +} + +static void +output_union_type_die (arg) + void *arg; +{ + tree type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_union_type); + sibling_attribute (); + equate_type_number_to_die_number (type); + name_attribute (type_tag (type)); + member_attribute (TYPE_CONTEXT (type)); + + /* If this type has been completed, then give it a byte_size attribute + and prepare to give a list of members. Otherwise, don't do either of + these things. In the latter case, we will not be generating a list + of members (since we don't have any idea what they might be for an + incomplete type). */ + + if (COMPLETE_TYPE_P (type)) + { + dienum_push (); + byte_size_attribute (type); + } +} + +/* Generate a special type of DIE used as a stand-in for a trailing ellipsis + at the end of an (ANSI prototyped) formal parameters list. */ + +static void +output_unspecified_parameters_die (arg) + void *arg; +{ + tree decl_or_type = arg; + + ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_unspecified_parameters); + sibling_attribute (); + + /* This kludge is here only for the sake of being compatible with what + the USL CI5 C compiler does. The specification of Dwarf Version 1 + doesn't say that TAG_unspecified_parameters DIEs should contain any + attributes other than the AT_sibling attribute, but they are certainly + allowed to contain additional attributes, and the CI5 compiler + generates AT_name, AT_fund_type, and AT_location attributes within + TAG_unspecified_parameters DIEs which appear in the child lists for + DIEs representing function definitions, so we do likewise here. */ + + if (TREE_CODE (decl_or_type) == FUNCTION_DECL && DECL_INITIAL (decl_or_type)) + { + name_attribute ("..."); + fund_type_attribute (FT_pointer); + /* location_attribute (?); */ + } +} + +static void +output_padded_null_die (arg) + void *arg ATTRIBUTE_UNUSED; +{ + ASM_OUTPUT_ALIGN (asm_out_file, 2); /* 2**2 == 4 */ +} + +/*************************** end of DIEs *********************************/ + +/* Generate some type of DIE. This routine generates the generic outer + wrapper stuff which goes around all types of DIE's (regardless of their + TAGs. All forms of DIEs start with a DIE-specific label, followed by a + DIE-length word, followed by the guts of the DIE itself. After the guts + of the DIE, there must always be a terminator label for the DIE. */ + +static void +output_die (die_specific_output_function, param) + void (*die_specific_output_function) PARAMS ((void *)); + void *param; +{ + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + current_dienum = NEXT_DIE_NUM; + NEXT_DIE_NUM = next_unused_dienum; + + sprintf (begin_label, DIE_BEGIN_LABEL_FMT, current_dienum); + sprintf (end_label, DIE_END_LABEL_FMT, current_dienum); + + /* Write a label which will act as the name for the start of this DIE. */ + + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + + /* Write the DIE-length word. */ + + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, end_label, begin_label); + + /* Fill in the guts of the DIE. */ + + next_unused_dienum++; + die_specific_output_function (param); + + /* Write a label which will act as the name for the end of this DIE. */ + + ASM_OUTPUT_LABEL (asm_out_file, end_label); +} + +static void +end_sibling_chain () +{ + char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + current_dienum = NEXT_DIE_NUM; + NEXT_DIE_NUM = next_unused_dienum; + + sprintf (begin_label, DIE_BEGIN_LABEL_FMT, current_dienum); + + /* Write a label which will act as the name for the start of this DIE. */ + + ASM_OUTPUT_LABEL (asm_out_file, begin_label); + + /* Write the DIE-length word. */ + + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 4); + + dienum_pop (); +} + +/* Generate a list of nameless TAG_formal_parameter DIEs (and perhaps a + TAG_unspecified_parameters DIE) to represent the types of the formal + parameters as specified in some function type specification (except + for those which appear as part of a function *definition*). + + Note that we must be careful here to output all of the parameter + DIEs *before* we output any DIEs needed to represent the types of + the formal parameters. This keeps svr4 SDB happy because it + (incorrectly) thinks that the first non-parameter DIE it sees ends + the formal parameter list. */ + +static void +output_formal_types (function_or_method_type) + tree function_or_method_type; +{ + tree link; + tree formal_type = NULL; + tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type); + + /* Set TREE_ASM_WRITTEN while processing the parameters, lest we + get bogus recursion when outputting tagged types local to a + function declaration. */ + int save_asm_written = TREE_ASM_WRITTEN (function_or_method_type); + TREE_ASM_WRITTEN (function_or_method_type) = 1; + + /* In the case where we are generating a formal types list for a C++ + non-static member function type, skip over the first thing on the + TYPE_ARG_TYPES list because it only represents the type of the + hidden `this pointer'. The debugger should be able to figure + out (without being explicitly told) that this non-static member + function type takes a `this pointer' and should be able to figure + what the type of that hidden parameter is from the AT_member + attribute of the parent TAG_subroutine_type DIE. */ + + if (TREE_CODE (function_or_method_type) == METHOD_TYPE) + first_parm_type = TREE_CHAIN (first_parm_type); + + /* Make our first pass over the list of formal parameter types and output + a TAG_formal_parameter DIE for each one. */ + + for (link = first_parm_type; link; link = TREE_CHAIN (link)) + { + formal_type = TREE_VALUE (link); + if (formal_type == void_type_node) + break; + + /* Output a (nameless) DIE to represent the formal parameter itself. */ + + output_die (output_formal_parameter_die, formal_type); + } + + /* If this function type has an ellipsis, add a TAG_unspecified_parameters + DIE to the end of the parameter list. */ + + if (formal_type != void_type_node) + output_die (output_unspecified_parameters_die, function_or_method_type); + + /* Make our second (and final) pass over the list of formal parameter types + and output DIEs to represent those types (as necessary). */ + + for (link = TYPE_ARG_TYPES (function_or_method_type); + link; + link = TREE_CHAIN (link)) + { + formal_type = TREE_VALUE (link); + if (formal_type == void_type_node) + break; + + output_type (formal_type, function_or_method_type); + } + + TREE_ASM_WRITTEN (function_or_method_type) = save_asm_written; +} + +/* Remember a type in the pending_types_list. */ + +static void +pend_type (type) + tree type; +{ + if (pending_types == pending_types_allocated) + { + pending_types_allocated += PENDING_TYPES_INCREMENT; + pending_types_list + = (tree *) xrealloc (pending_types_list, + sizeof (tree) * pending_types_allocated); + } + pending_types_list[pending_types++] = type; + + /* Mark the pending type as having been output already (even though + it hasn't been). This prevents the type from being added to the + pending_types_list more than once. */ + + TREE_ASM_WRITTEN (type) = 1; +} + +/* Return nonzero if it is legitimate to output DIEs to represent a + given type while we are generating the list of child DIEs for some + DIE (e.g. a function or lexical block DIE) associated with a given scope. + + See the comments within the function for a description of when it is + considered legitimate to output DIEs for various kinds of types. + + Note that TYPE_CONTEXT(type) may be NULL (to indicate global scope) + or it may point to a BLOCK node (for types local to a block), or to a + FUNCTION_DECL node (for types local to the heading of some function + definition), or to a FUNCTION_TYPE node (for types local to the + prototyped parameter list of a function type specification), or to a + RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE node + (in the case of C++ nested types). + + The `scope' parameter should likewise be NULL or should point to a + BLOCK node, a FUNCTION_DECL node, a FUNCTION_TYPE node, a RECORD_TYPE + node, a UNION_TYPE node, or a QUAL_UNION_TYPE node. + + This function is used only for deciding when to "pend" and when to + "un-pend" types to/from the pending_types_list. + + Note that we sometimes make use of this "type pending" feature in a + rather twisted way to temporarily delay the production of DIEs for the + types of formal parameters. (We do this just to make svr4 SDB happy.) + It order to delay the production of DIEs representing types of formal + parameters, callers of this function supply `fake_containing_scope' as + the `scope' parameter to this function. Given that fake_containing_scope + is a tagged type which is *not* the containing scope for *any* other type, + the desired effect is achieved, i.e. output of DIEs representing types + is temporarily suspended, and any type DIEs which would have otherwise + been output are instead placed onto the pending_types_list. Later on, + we force these (temporarily pended) types to be output simply by calling + `output_pending_types_for_scope' with an actual argument equal to the + true scope of the types we temporarily pended. */ + +static inline int +type_ok_for_scope (type, scope) + tree type; + tree scope; +{ + /* Tagged types (i.e. struct, union, and enum types) must always be + output only in the scopes where they actually belong (or else the + scoping of their own tag names and the scoping of their member + names will be incorrect). Non-tagged-types on the other hand can + generally be output anywhere, except that svr4 SDB really doesn't + want to see them nested within struct or union types, so here we + say it is always OK to immediately output any such a (non-tagged) + type, so long as we are not within such a context. Note that the + only kinds of non-tagged types which we will be dealing with here + (for C and C++ anyway) will be array types and function types. */ + + return is_tagged_type (type) + ? (TYPE_CONTEXT (type) == scope + /* Ignore namespaces for the moment. */ + || (scope == NULL_TREE + && TREE_CODE (TYPE_CONTEXT (type)) == NAMESPACE_DECL) + || (scope == NULL_TREE && is_tagged_type (TYPE_CONTEXT (type)) + && TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))) + : (scope == NULL_TREE || ! is_tagged_type (scope)); +} + +/* Output any pending types (from the pending_types list) which we can output + now (taking into account the scope that we are working on now). + + For each type output, remove the given type from the pending_types_list + *before* we try to output it. + + Note that we have to process the list in beginning-to-end order, + because the call made here to output_type may cause yet more types + to be added to the end of the list, and we may have to output some + of them too. */ + +static void +output_pending_types_for_scope (containing_scope) + tree containing_scope; +{ + unsigned i; + + for (i = 0; i < pending_types; ) + { + tree type = pending_types_list[i]; + + if (type_ok_for_scope (type, containing_scope)) + { + tree *mover; + tree *limit; + + pending_types--; + limit = &pending_types_list[pending_types]; + for (mover = &pending_types_list[i]; mover < limit; mover++) + *mover = *(mover+1); + + /* Un-mark the type as having been output already (because it + hasn't been, really). Then call output_type to generate a + Dwarf representation of it. */ + + TREE_ASM_WRITTEN (type) = 0; + output_type (type, containing_scope); + + /* Don't increment the loop counter in this case because we + have shifted all of the subsequent pending types down one + element in the pending_types_list array. */ + } + else + i++; + } +} + +/* Remember a type in the incomplete_types_list. */ + +static void +add_incomplete_type (type) + tree type; +{ + if (incomplete_types == incomplete_types_allocated) + { + incomplete_types_allocated += INCOMPLETE_TYPES_INCREMENT; + incomplete_types_list + = (tree *) xrealloc (incomplete_types_list, + sizeof (tree) * incomplete_types_allocated); + } + + incomplete_types_list[incomplete_types++] = type; +} + +/* Walk through the list of incomplete types again, trying once more to + emit full debugging info for them. */ + +static void +retry_incomplete_types () +{ + tree type; + + finalizing = 1; + while (incomplete_types) + { + --incomplete_types; + type = incomplete_types_list[incomplete_types]; + output_type (type, NULL_TREE); + } +} + +static void +output_type (type, containing_scope) + tree type; + tree containing_scope; +{ + if (type == 0 || type == error_mark_node) + return; + + /* We are going to output a DIE to represent the unqualified version of + this type (i.e. without any const or volatile qualifiers) so get + the main variant (i.e. the unqualified version) of this type now. */ + + type = type_main_variant (type); + + if (TREE_ASM_WRITTEN (type)) + { + if (finalizing && AGGREGATE_TYPE_P (type)) + { + tree member; + + /* Some of our nested types might not have been defined when we + were written out before; force them out now. */ + + for (member = TYPE_FIELDS (type); member; + member = TREE_CHAIN (member)) + if (TREE_CODE (member) == TYPE_DECL + && ! TREE_ASM_WRITTEN (TREE_TYPE (member))) + output_type (TREE_TYPE (member), containing_scope); + } + return; + } + + /* If this is a nested type whose containing class hasn't been + written out yet, writing it out will cover this one, too. */ + + if (TYPE_CONTEXT (type) + && TYPE_P (TYPE_CONTEXT (type)) + && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) + { + output_type (TYPE_CONTEXT (type), containing_scope); + return; + } + + /* Don't generate any DIEs for this type now unless it is OK to do so + (based upon what `type_ok_for_scope' tells us). */ + + if (! type_ok_for_scope (type, containing_scope)) + { + pend_type (type); + return; + } + + switch (TREE_CODE (type)) + { + case ERROR_MARK: + break; + + case VECTOR_TYPE: + output_type (TYPE_DEBUG_REPRESENTATION_TYPE (type), containing_scope); + break; + + case POINTER_TYPE: + case REFERENCE_TYPE: + /* Prevent infinite recursion in cases where this is a recursive + type. Recursive types are possible in Ada. */ + TREE_ASM_WRITTEN (type) = 1; + /* For these types, all that is required is that we output a DIE + (or a set of DIEs) to represent the "basis" type. */ + output_type (TREE_TYPE (type), containing_scope); + break; + + case OFFSET_TYPE: + /* This code is used for C++ pointer-to-data-member types. */ + /* Output a description of the relevant class type. */ + output_type (TYPE_OFFSET_BASETYPE (type), containing_scope); + /* Output a description of the type of the object pointed to. */ + output_type (TREE_TYPE (type), containing_scope); + /* Now output a DIE to represent this pointer-to-data-member type + itself. */ + output_die (output_ptr_to_mbr_type_die, type); + break; + + case SET_TYPE: + output_type (TYPE_DOMAIN (type), containing_scope); + output_die (output_set_type_die, type); + break; + + case FILE_TYPE: + output_type (TREE_TYPE (type), containing_scope); + abort (); /* No way to represent these in Dwarf yet! */ + break; + + case FUNCTION_TYPE: + /* Force out return type (in case it wasn't forced out already). */ + output_type (TREE_TYPE (type), containing_scope); + output_die (output_subroutine_type_die, type); + output_formal_types (type); + end_sibling_chain (); + break; + + case METHOD_TYPE: + /* Force out return type (in case it wasn't forced out already). */ + output_type (TREE_TYPE (type), containing_scope); + output_die (output_subroutine_type_die, type); + output_formal_types (type); + end_sibling_chain (); + break; + + case ARRAY_TYPE: + if (TYPE_STRING_FLAG (type) && TREE_CODE(TREE_TYPE(type)) == CHAR_TYPE) + { + output_type (TREE_TYPE (type), containing_scope); + output_die (output_string_type_die, type); + } + else + { + tree element_type; + + element_type = TREE_TYPE (type); + while (TREE_CODE (element_type) == ARRAY_TYPE) + element_type = TREE_TYPE (element_type); + + output_type (element_type, containing_scope); + output_die (output_array_type_die, type); + } + break; + + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + + /* For a non-file-scope tagged type, we can always go ahead and + output a Dwarf description of this type right now, even if + the type in question is still incomplete, because if this + local type *was* ever completed anywhere within its scope, + that complete definition would already have been attached to + this RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE or ENUMERAL_TYPE + node by the time we reach this point. That's true because of the + way the front-end does its processing of file-scope declarations (of + functions and class types) within which other types might be + nested. The C and C++ front-ends always gobble up such "local + scope" things en-mass before they try to output *any* debugging + information for any of the stuff contained inside them and thus, + we get the benefit here of what is (in effect) a pre-resolution + of forward references to tagged types in local scopes. + + Note however that for file-scope tagged types we cannot assume + that such pre-resolution of forward references has taken place. + A given file-scope tagged type may appear to be incomplete when + we reach this point, but it may yet be given a full definition + (at file-scope) later on during compilation. In order to avoid + generating a premature (and possibly incorrect) set of Dwarf + DIEs for such (as yet incomplete) file-scope tagged types, we + generate nothing at all for as-yet incomplete file-scope tagged + types here unless we are making our special "finalization" pass + for file-scope things at the very end of compilation. At that + time, we will certainly know as much about each file-scope tagged + type as we are ever going to know, so at that point in time, we + can safely generate correct Dwarf descriptions for these file- + scope tagged types. */ + + if (!COMPLETE_TYPE_P (type) + && (TYPE_CONTEXT (type) == NULL + || AGGREGATE_TYPE_P (TYPE_CONTEXT (type)) + || TREE_CODE (TYPE_CONTEXT (type)) == NAMESPACE_DECL) + && !finalizing) + { + /* We don't need to do this for function-local types. */ + if (! decl_function_context (TYPE_STUB_DECL (type))) + add_incomplete_type (type); + return; /* EARLY EXIT! Avoid setting TREE_ASM_WRITTEN. */ + } + + /* Prevent infinite recursion in cases where the type of some + member of this type is expressed in terms of this type itself. */ + + TREE_ASM_WRITTEN (type) = 1; + + /* Output a DIE to represent the tagged type itself. */ + + switch (TREE_CODE (type)) + { + case ENUMERAL_TYPE: + output_die (output_enumeration_type_die, type); + return; /* a special case -- nothing left to do so just return */ + + case RECORD_TYPE: + output_die (output_structure_type_die, type); + break; + + case UNION_TYPE: + case QUAL_UNION_TYPE: + output_die (output_union_type_die, type); + break; + + default: + abort (); /* Should never happen. */ + } + + /* If this is not an incomplete type, output descriptions of + each of its members. + + Note that as we output the DIEs necessary to represent the + members of this record or union type, we will also be trying + to output DIEs to represent the *types* of those members. + However the `output_type' function (above) will specifically + avoid generating type DIEs for member types *within* the list + of member DIEs for this (containing) type except for those + types (of members) which are explicitly marked as also being + members of this (containing) type themselves. The g++ front- + end can force any given type to be treated as a member of some + other (containing) type by setting the TYPE_CONTEXT of the + given (member) type to point to the TREE node representing the + appropriate (containing) type. + */ + + if (COMPLETE_TYPE_P (type)) + { + /* First output info about the base classes. */ + if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type)) + { + register tree bases = TYPE_BINFO_BASETYPES (type); + register int n_bases = TREE_VEC_LENGTH (bases); + register int i; + + for (i = 0; i < n_bases; i++) + { + tree binfo = TREE_VEC_ELT (bases, i); + output_type (BINFO_TYPE (binfo), containing_scope); + output_die (output_inheritance_die, binfo); + } + } + + ++in_class; + + { + tree normal_member; + + /* Now output info about the data members and type members. */ + + for (normal_member = TYPE_FIELDS (type); + normal_member; + normal_member = TREE_CHAIN (normal_member)) + output_decl (normal_member, type); + } + + { + tree func_member; + + /* Now output info about the function members (if any). */ + + for (func_member = TYPE_METHODS (type); + func_member; + func_member = TREE_CHAIN (func_member)) + { + /* Don't include clones in the member list. */ + if (DECL_ABSTRACT_ORIGIN (func_member)) + continue; + + output_decl (func_member, type); + } + } + + --in_class; + + /* RECORD_TYPEs, UNION_TYPEs, and QUAL_UNION_TYPEs are themselves + scopes (at least in C++) so we must now output any nested + pending types which are local just to this type. */ + + output_pending_types_for_scope (type); + + end_sibling_chain (); /* Terminate member chain. */ + } + + break; + + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case COMPLEX_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + break; /* No DIEs needed for fundamental types. */ + + case LANG_TYPE: /* No Dwarf representation currently defined. */ + break; + + default: + abort (); + } + + TREE_ASM_WRITTEN (type) = 1; +} + +static void +output_tagged_type_instantiation (type) + tree type; +{ + if (type == 0 || type == error_mark_node) + return; + + /* We are going to output a DIE to represent the unqualified version of + this type (i.e. without any const or volatile qualifiers) so make + sure that we have the main variant (i.e. the unqualified version) of + this type now. */ + + if (type != type_main_variant (type)) + abort (); + + if (!TREE_ASM_WRITTEN (type)) + abort (); + + switch (TREE_CODE (type)) + { + case ERROR_MARK: + break; + + case ENUMERAL_TYPE: + output_die (output_inlined_enumeration_type_die, type); + break; + + case RECORD_TYPE: + output_die (output_inlined_structure_type_die, type); + break; + + case UNION_TYPE: + case QUAL_UNION_TYPE: + output_die (output_inlined_union_type_die, type); + break; + + default: + abort (); /* Should never happen. */ + } +} + +/* Output a TAG_lexical_block DIE followed by DIEs to represent all of + the things which are local to the given block. */ + +static void +output_block (stmt, depth) + tree stmt; + int depth; +{ + int must_output_die = 0; + tree origin; + enum tree_code origin_code; + + /* Ignore blocks never really used to make RTL. */ + + if (! stmt || ! TREE_USED (stmt) + || (!TREE_ASM_WRITTEN (stmt) && !BLOCK_ABSTRACT (stmt))) + return; + + /* Determine the "ultimate origin" of this block. This block may be an + inlined instance of an inlined instance of inline function, so we + have to trace all of the way back through the origin chain to find + out what sort of node actually served as the original seed for the + creation of the current block. */ + + origin = block_ultimate_origin (stmt); + origin_code = (origin != NULL) ? TREE_CODE (origin) : ERROR_MARK; + + /* Determine if we need to output any Dwarf DIEs at all to represent this + block. */ + + if (origin_code == FUNCTION_DECL) + /* The outer scopes for inlinings *must* always be represented. We + generate TAG_inlined_subroutine DIEs for them. (See below.) */ + must_output_die = 1; + else + { + /* In the case where the current block represents an inlining of the + "body block" of an inline function, we must *NOT* output any DIE + for this block because we have already output a DIE to represent + the whole inlined function scope and the "body block" of any + function doesn't really represent a different scope according to + ANSI C rules. So we check here to make sure that this block does + not represent a "body block inlining" before trying to set the + `must_output_die' flag. */ + + if (! is_body_block (origin ? origin : stmt)) + { + /* Determine if this block directly contains any "significant" + local declarations which we will need to output DIEs for. */ + + if (debug_info_level > DINFO_LEVEL_TERSE) + /* We are not in terse mode so *any* local declaration counts + as being a "significant" one. */ + must_output_die = (BLOCK_VARS (stmt) != NULL); + else + { + tree decl; + + /* We are in terse mode, so only local (nested) function + definitions count as "significant" local declarations. */ + + for (decl = BLOCK_VARS (stmt); decl; decl = TREE_CHAIN (decl)) + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) + { + must_output_die = 1; + break; + } + } + } + } + + /* It would be a waste of space to generate a Dwarf TAG_lexical_block + DIE for any block which contains no significant local declarations + at all. Rather, in such cases we just call `output_decls_for_scope' + so that any needed Dwarf info for any sub-blocks will get properly + generated. Note that in terse mode, our definition of what constitutes + a "significant" local declaration gets restricted to include only + inlined function instances and local (nested) function definitions. */ + + if (origin_code == FUNCTION_DECL && BLOCK_ABSTRACT (stmt)) + /* We don't care about an abstract inlined subroutine. */; + else if (must_output_die) + { + output_die ((origin_code == FUNCTION_DECL) + ? output_inlined_subroutine_die + : output_lexical_block_die, + stmt); + output_decls_for_scope (stmt, depth); + end_sibling_chain (); + } + else + output_decls_for_scope (stmt, depth); +} + +/* Output all of the decls declared within a given scope (also called + a `binding contour') and (recursively) all of it's sub-blocks. */ + +static void +output_decls_for_scope (stmt, depth) + tree stmt; + int depth; +{ + /* Ignore blocks never really used to make RTL. */ + + if (! stmt || ! TREE_USED (stmt)) + return; + + /* Output the DIEs to represent all of the data objects, functions, + typedefs, and tagged types declared directly within this block + but not within any nested sub-blocks. */ + + { + tree decl; + + for (decl = BLOCK_VARS (stmt); decl; decl = TREE_CHAIN (decl)) + output_decl (decl, stmt); + } + + output_pending_types_for_scope (stmt); + + /* Output the DIEs to represent all sub-blocks (and the items declared + therein) of this block. */ + + { + tree subblocks; + + for (subblocks = BLOCK_SUBBLOCKS (stmt); + subblocks; + subblocks = BLOCK_CHAIN (subblocks)) + output_block (subblocks, depth + 1); + } +} + +/* Is this a typedef we can avoid emitting? */ + +static inline int +is_redundant_typedef (decl) + tree decl; +{ + if (TYPE_DECL_IS_STUB (decl)) + return 1; + if (DECL_ARTIFICIAL (decl) + && DECL_CONTEXT (decl) + && is_tagged_type (DECL_CONTEXT (decl)) + && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL + && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl)))) + /* Also ignore the artificial member typedef for the class name. */ + return 1; + return 0; +} + +/* Output Dwarf .debug information for a decl described by DECL. */ + +static void +output_decl (decl, containing_scope) + tree decl; + tree containing_scope; +{ + /* Make a note of the decl node we are going to be working on. We may + need to give the user the source coordinates of where it appeared in + case we notice (later on) that something about it looks screwy. */ + + dwarf_last_decl = decl; + + if (TREE_CODE (decl) == ERROR_MARK) + return; + + /* If a structure is declared within an initialization, e.g. as the + operand of a sizeof, then it will not have a name. We don't want + to output a DIE for it, as the tree nodes are in the temporary obstack */ + + if ((TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE) + && ((DECL_NAME (decl) == 0 && TYPE_NAME (TREE_TYPE (decl)) == 0) + || (TYPE_FIELDS (TREE_TYPE (decl)) + && (TREE_CODE (TYPE_FIELDS (TREE_TYPE (decl))) == ERROR_MARK)))) + return; + + /* If this ..._DECL node is marked to be ignored, then ignore it. */ + + if (DECL_IGNORED_P (decl)) + return; + + switch (TREE_CODE (decl)) + { + case CONST_DECL: + /* The individual enumerators of an enum type get output when we + output the Dwarf representation of the relevant enum type itself. */ + break; + + case FUNCTION_DECL: + /* If we are in terse mode, don't output any DIEs to represent + mere function declarations. Also, if we are conforming + to the DWARF version 1 specification, don't output DIEs for + mere function declarations. */ + + if (DECL_INITIAL (decl) == NULL_TREE) +#if (DWARF_VERSION > 1) + if (debug_info_level <= DINFO_LEVEL_TERSE) +#endif + break; + + /* Before we describe the FUNCTION_DECL itself, make sure that we + have described its return type. */ + + output_type (TREE_TYPE (TREE_TYPE (decl)), containing_scope); + + { + /* And its containing type. */ + register tree origin = decl_class_context (decl); + if (origin) + output_type (origin, containing_scope); + } + + /* If we're emitting an out-of-line copy of an inline function, + set up to refer to the abstract instance emitted from + dwarfout_deferred_inline_function. */ + if (DECL_INLINE (decl) && ! DECL_ABSTRACT (decl) + && ! (containing_scope && TYPE_P (containing_scope))) + set_decl_origin_self (decl); + + /* If the following DIE will represent a function definition for a + function with "extern" linkage, output a special "pubnames" DIE + label just ahead of the actual DIE. A reference to this label + was already generated in the .debug_pubnames section sub-entry + for this function definition. */ + + if (TREE_PUBLIC (decl)) + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + sprintf (label, PUB_DIE_LABEL_FMT, next_pubname_number++); + ASM_OUTPUT_LABEL (asm_out_file, label); + } + + /* Now output a DIE to represent the function itself. */ + + output_die (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl) + ? output_global_subroutine_die + : output_local_subroutine_die, + decl); + + /* Now output descriptions of the arguments for this function. + This gets (unnecessarily?) complex because of the fact that + the DECL_ARGUMENT list for a FUNCTION_DECL doesn't indicate + cases where there was a trailing `...' at the end of the formal + parameter list. In order to find out if there was a trailing + ellipsis or not, we must instead look at the type associated + with the FUNCTION_DECL. This will be a node of type FUNCTION_TYPE. + If the chain of type nodes hanging off of this FUNCTION_TYPE node + ends with a void_type_node then there should *not* be an ellipsis + at the end. */ + + /* In the case where we are describing a mere function declaration, all + we need to do here (and all we *can* do here) is to describe + the *types* of its formal parameters. */ + + if (decl != current_function_decl || in_class) + output_formal_types (TREE_TYPE (decl)); + else + { + /* Generate DIEs to represent all known formal parameters */ + + tree arg_decls = DECL_ARGUMENTS (decl); + tree parm; + + /* WARNING! Kludge zone ahead! Here we have a special + hack for svr4 SDB compatibility. Instead of passing the + current FUNCTION_DECL node as the second parameter (i.e. + the `containing_scope' parameter) to `output_decl' (as + we ought to) we instead pass a pointer to our own private + fake_containing_scope node. That node is a RECORD_TYPE + node which NO OTHER TYPE may ever actually be a member of. + + This pointer will ultimately get passed into `output_type' + as its `containing_scope' parameter. `Output_type' will + then perform its part in the hack... i.e. it will pend + the type of the formal parameter onto the pending_types + list. Later on, when we are done generating the whole + sequence of formal parameter DIEs for this function + definition, we will un-pend all previously pended types + of formal parameters for this function definition. + + This whole kludge prevents any type DIEs from being + mixed in with the formal parameter DIEs. That's good + because svr4 SDB believes that the list of formal + parameter DIEs for a function ends wherever the first + non-formal-parameter DIE appears. Thus, we have to + keep the formal parameter DIEs segregated. They must + all appear (consecutively) at the start of the list of + children for the DIE representing the function definition. + Then (and only then) may we output any additional DIEs + needed to represent the types of these formal parameters. + */ + + /* + When generating DIEs, generate the unspecified_parameters + DIE instead if we come across the arg "__builtin_va_alist" + */ + + for (parm = arg_decls; parm; parm = TREE_CHAIN (parm)) + if (TREE_CODE (parm) == PARM_DECL) + { + if (DECL_NAME(parm) && + !strcmp(IDENTIFIER_POINTER(DECL_NAME(parm)), + "__builtin_va_alist") ) + output_die (output_unspecified_parameters_die, decl); + else + output_decl (parm, fake_containing_scope); + } + + /* + Now that we have finished generating all of the DIEs to + represent the formal parameters themselves, force out + any DIEs needed to represent their types. We do this + simply by un-pending all previously pended types which + can legitimately go into the chain of children DIEs for + the current FUNCTION_DECL. + */ + + output_pending_types_for_scope (decl); + + /* + Decide whether we need an unspecified_parameters DIE at the end. + There are 2 more cases to do this for: + 1) the ansi ... declaration - this is detectable when the end + of the arg list is not a void_type_node + 2) an unprototyped function declaration (not a definition). This + just means that we have no info about the parameters at all. + */ + + { + tree fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); + + if (fn_arg_types) + { + /* this is the prototyped case, check for ... */ + if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node) + output_die (output_unspecified_parameters_die, decl); + } + else + { + /* this is unprototyped, check for undefined (just declaration) */ + if (!DECL_INITIAL (decl)) + output_die (output_unspecified_parameters_die, decl); + } + } + + /* Output Dwarf info for all of the stuff within the body of the + function (if it has one - it may be just a declaration). */ + + { + tree outer_scope = DECL_INITIAL (decl); + + if (outer_scope && TREE_CODE (outer_scope) != ERROR_MARK) + { + /* Note that here, `outer_scope' is a pointer to the outermost + BLOCK node created to represent a function. + This outermost BLOCK actually represents the outermost + binding contour for the function, i.e. the contour in which + the function's formal parameters and labels get declared. + + Curiously, it appears that the front end doesn't actually + put the PARM_DECL nodes for the current function onto the + BLOCK_VARS list for this outer scope. (They are strung + off of the DECL_ARGUMENTS list for the function instead.) + The BLOCK_VARS list for the `outer_scope' does provide us + with a list of the LABEL_DECL nodes for the function however, + and we output DWARF info for those here. + + Just within the `outer_scope' there will be a BLOCK node + representing the function's outermost pair of curly braces, + and any blocks used for the base and member initializers of + a C++ constructor function. */ + + output_decls_for_scope (outer_scope, 0); + + /* Finally, force out any pending types which are local to the + outermost block of this function definition. These will + all have a TYPE_CONTEXT which points to the FUNCTION_DECL + node itself. */ + + output_pending_types_for_scope (decl); + } + } + } + + /* Generate a terminator for the list of stuff `owned' by this + function. */ + + end_sibling_chain (); + + break; + + case TYPE_DECL: + /* If we are in terse mode, don't generate any DIEs to represent + any actual typedefs. Note that even when we are in terse mode, + we must still output DIEs to represent those tagged types which + are used (directly or indirectly) in the specification of either + a return type or a formal parameter type of some function. */ + + if (debug_info_level <= DINFO_LEVEL_TERSE) + if (! TYPE_DECL_IS_STUB (decl) + || (! TYPE_USED_FOR_FUNCTION (TREE_TYPE (decl)) && ! in_class)) + return; + + /* In the special case of a TYPE_DECL node representing + the declaration of some type tag, if the given TYPE_DECL is + marked as having been instantiated from some other (original) + TYPE_DECL node (e.g. one which was generated within the original + definition of an inline function) we have to generate a special + (abbreviated) TAG_structure_type, TAG_union_type, or + TAG_enumeration-type DIE here. */ + + if (TYPE_DECL_IS_STUB (decl) && DECL_ABSTRACT_ORIGIN (decl)) + { + output_tagged_type_instantiation (TREE_TYPE (decl)); + return; + } + + output_type (TREE_TYPE (decl), containing_scope); + + if (! is_redundant_typedef (decl)) + /* Output a DIE to represent the typedef itself. */ + output_die (output_typedef_die, decl); + break; + + case LABEL_DECL: + if (debug_info_level >= DINFO_LEVEL_NORMAL) + output_die (output_label_die, decl); + break; + + case VAR_DECL: + /* If we are conforming to the DWARF version 1 specification, don't + generated any DIEs to represent mere external object declarations. */ + +#if (DWARF_VERSION <= 1) + if (DECL_EXTERNAL (decl) && ! TREE_PUBLIC (decl)) + break; +#endif + + /* If we are in terse mode, don't generate any DIEs to represent + any variable declarations or definitions. */ + + if (debug_info_level <= DINFO_LEVEL_TERSE) + break; + + /* Output any DIEs that are needed to specify the type of this data + object. */ + + output_type (TREE_TYPE (decl), containing_scope); + + { + /* And its containing type. */ + register tree origin = decl_class_context (decl); + if (origin) + output_type (origin, containing_scope); + } + + /* If the following DIE will represent a data object definition for a + data object with "extern" linkage, output a special "pubnames" DIE + label just ahead of the actual DIE. A reference to this label + was already generated in the .debug_pubnames section sub-entry + for this data object definition. */ + + if (TREE_PUBLIC (decl) && ! DECL_ABSTRACT (decl)) + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + sprintf (label, PUB_DIE_LABEL_FMT, next_pubname_number++); + ASM_OUTPUT_LABEL (asm_out_file, label); + } + + /* Now output the DIE to represent the data object itself. This gets + complicated because of the possibility that the VAR_DECL really + represents an inlined instance of a formal parameter for an inline + function. */ + + { + void (*func) PARAMS ((void *)); + register tree origin = decl_ultimate_origin (decl); + + if (origin != NULL && TREE_CODE (origin) == PARM_DECL) + func = output_formal_parameter_die; + else + { + if (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)) + func = output_global_variable_die; + else + func = output_local_variable_die; + } + output_die (func, decl); + } + break; + + case FIELD_DECL: + /* Ignore the nameless fields that are used to skip bits. */ + if (DECL_NAME (decl) != 0) + { + output_type (member_declared_type (decl), containing_scope); + output_die (output_member_die, decl); + } + break; + + case PARM_DECL: + /* Force out the type of this formal, if it was not forced out yet. + Note that here we can run afoul of a bug in "classic" svr4 SDB. + It should be able to grok the presence of type DIEs within a list + of TAG_formal_parameter DIEs, but it doesn't. */ + + output_type (TREE_TYPE (decl), containing_scope); + output_die (output_formal_parameter_die, decl); + break; + + case NAMESPACE_DECL: + /* Ignore for now. */ + break; + + default: + abort (); + } +} + +/* Output debug information for a function. */ +static void +dwarfout_function_decl (decl) + tree decl; +{ + dwarfout_file_scope_decl (decl, 0); +} + +/* Debug information for a global DECL. Called from toplev.c after + compilation proper has finished. */ +static void +dwarfout_global_decl (decl) + tree decl; +{ + /* Output DWARF information for file-scope tentative data object + declarations, file-scope (extern) function declarations (which + had no corresponding body) and file-scope tagged type + declarations and definitions which have not yet been forced out. */ + + if (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl)) + dwarfout_file_scope_decl (decl, 1); +} + +/* DECL is an inline function, whose body is present, but which is not + being output at this point. (We're putting that off until we need + to do it.) */ +static void +dwarfout_deferred_inline_function (decl) + tree decl; +{ + /* Generate the DWARF info for the "abstract" instance of a function + which we may later generate inlined and/or out-of-line instances + of. */ + if ((DECL_INLINE (decl) || DECL_ABSTRACT (decl)) + && ! DECL_ABSTRACT_ORIGIN (decl)) + { + /* The front-end may not have set CURRENT_FUNCTION_DECL, but the + DWARF code expects it to be set in this case. Intuitively, + DECL is the function we just finished defining, so setting + CURRENT_FUNCTION_DECL is sensible. */ + tree saved_cfd = current_function_decl; + int was_abstract = DECL_ABSTRACT (decl); + current_function_decl = decl; + + /* Let the DWARF code do its work. */ + set_decl_abstract_flags (decl, 1); + dwarfout_file_scope_decl (decl, 0); + if (! was_abstract) + set_decl_abstract_flags (decl, 0); + + /* Reset CURRENT_FUNCTION_DECL. */ + current_function_decl = saved_cfd; + } +} + +static void +dwarfout_file_scope_decl (decl, set_finalizing) + tree decl; + int set_finalizing; +{ + if (TREE_CODE (decl) == ERROR_MARK) + return; + + /* If this ..._DECL node is marked to be ignored, then ignore it. */ + + if (DECL_IGNORED_P (decl)) + return; + + switch (TREE_CODE (decl)) + { + case FUNCTION_DECL: + + /* Ignore this FUNCTION_DECL if it refers to a builtin declaration of + a builtin function. Explicit programmer-supplied declarations of + these same functions should NOT be ignored however. */ + + if (DECL_EXTERNAL (decl) && DECL_FUNCTION_CODE (decl)) + return; + + /* What we would really like to do here is to filter out all mere + file-scope declarations of file-scope functions which are never + referenced later within this translation unit (and keep all of + ones that *are* referenced later on) but we aren't clairvoyant, + so we have no idea which functions will be referenced in the + future (i.e. later on within the current translation unit). + So here we just ignore all file-scope function declarations + which are not also definitions. If and when the debugger needs + to know something about these functions, it will have to hunt + around and find the DWARF information associated with the + *definition* of the function. + + Note that we can't just check `DECL_EXTERNAL' to find out which + FUNCTION_DECL nodes represent definitions and which ones represent + mere declarations. We have to check `DECL_INITIAL' instead. That's + because the C front-end supports some weird semantics for "extern + inline" function definitions. These can get inlined within the + current translation unit (an thus, we need to generate DWARF info + for their abstract instances so that the DWARF info for the + concrete inlined instances can have something to refer to) but + the compiler never generates any out-of-lines instances of such + things (despite the fact that they *are* definitions). The + important point is that the C front-end marks these "extern inline" + functions as DECL_EXTERNAL, but we need to generate DWARF for them + anyway. + + Note that the C++ front-end also plays some similar games for inline + function definitions appearing within include files which also + contain `#pragma interface' pragmas. */ + + if (DECL_INITIAL (decl) == NULL_TREE) + return; + + if (TREE_PUBLIC (decl) + && ! DECL_EXTERNAL (decl) + && ! DECL_ABSTRACT (decl)) + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + /* Output a .debug_pubnames entry for a public function + defined in this compilation unit. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_PUBNAMES_SECTION); + sprintf (label, PUB_DIE_LABEL_FMT, next_pubname_number); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, label); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, + IDENTIFIER_POINTER (DECL_NAME (decl))); + ASM_OUTPUT_POP_SECTION (asm_out_file); + } + + break; + + case VAR_DECL: + + /* Ignore this VAR_DECL if it refers to a file-scope extern data + object declaration and if the declaration was never even + referenced from within this entire compilation unit. We + suppress these DIEs in order to save space in the .debug section + (by eliminating entries which are probably useless). Note that + we must not suppress block-local extern declarations (whether + used or not) because that would screw-up the debugger's name + lookup mechanism and cause it to miss things which really ought + to be in scope at a given point. */ + + if (DECL_EXTERNAL (decl) && !TREE_USED (decl)) + return; + + if (TREE_PUBLIC (decl) + && ! DECL_EXTERNAL (decl) + && GET_CODE (DECL_RTL (decl)) == MEM + && ! DECL_ABSTRACT (decl)) + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (debug_info_level >= DINFO_LEVEL_NORMAL) + { + /* Output a .debug_pubnames entry for a public variable + defined in this compilation unit. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_PUBNAMES_SECTION); + sprintf (label, PUB_DIE_LABEL_FMT, next_pubname_number); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, label); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, + IDENTIFIER_POINTER (DECL_NAME (decl))); + ASM_OUTPUT_POP_SECTION (asm_out_file); + } + + if (DECL_INITIAL (decl) == NULL) + { + /* Output a .debug_aranges entry for a public variable + which is tentatively defined in this compilation unit. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_ARANGES_SECTION); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, + (unsigned) int_size_in_bytes (TREE_TYPE (decl))); + ASM_OUTPUT_POP_SECTION (asm_out_file); + } + } + + /* If we are in terse mode, don't generate any DIEs to represent + any variable declarations or definitions. */ + + if (debug_info_level <= DINFO_LEVEL_TERSE) + return; + + break; + + case TYPE_DECL: + /* Don't bother trying to generate any DIEs to represent any of the + normal built-in types for the language we are compiling, except + in cases where the types in question are *not* DWARF fundamental + types. We make an exception in the case of non-fundamental types + for the sake of objective C (and perhaps C++) because the GNU + front-ends for these languages may in fact create certain "built-in" + types which are (for example) RECORD_TYPEs. In such cases, we + really need to output these (non-fundamental) types because other + DIEs may contain references to them. */ + + /* Also ignore language dependent types here, because they are probably + also built-in types. If we didn't ignore them, then we would get + references to undefined labels because output_type doesn't support + them. So, for now, we need to ignore them to avoid assembler + errors. */ + + /* ??? This code is different than the equivalent code in dwarf2out.c. + The dwarf2out.c code is probably more correct. */ + + if (DECL_SOURCE_LINE (decl) == 0 + && (type_is_fundamental (TREE_TYPE (decl)) + || TREE_CODE (TREE_TYPE (decl)) == LANG_TYPE)) + return; + + /* If we are in terse mode, don't generate any DIEs to represent + any actual typedefs. Note that even when we are in terse mode, + we must still output DIEs to represent those tagged types which + are used (directly or indirectly) in the specification of either + a return type or a formal parameter type of some function. */ + + if (debug_info_level <= DINFO_LEVEL_TERSE) + if (! TYPE_DECL_IS_STUB (decl) + || ! TYPE_USED_FOR_FUNCTION (TREE_TYPE (decl))) + return; + + break; + + default: + return; + } + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SECTION); + finalizing = set_finalizing; + output_decl (decl, NULL_TREE); + + /* NOTE: The call above to `output_decl' may have caused one or more + file-scope named types (i.e. tagged types) to be placed onto the + pending_types_list. We have to get those types off of that list + at some point, and this is the perfect time to do it. If we didn't + take them off now, they might still be on the list when cc1 finally + exits. That might be OK if it weren't for the fact that when we put + types onto the pending_types_list, we set the TREE_ASM_WRITTEN flag + for these types, and that causes them never to be output unless + `output_pending_types_for_scope' takes them off of the list and un-sets + their TREE_ASM_WRITTEN flags. */ + + output_pending_types_for_scope (NULL_TREE); + + /* The above call should have totally emptied the pending_types_list + if this is not a nested function or class. If this is a nested type, + then the remaining pending_types will be emitted when the containing type + is handled. */ + + if (! DECL_CONTEXT (decl)) + { + if (pending_types != 0) + abort (); + } + + ASM_OUTPUT_POP_SECTION (asm_out_file); +} + +/* Output a marker (i.e. a label) for the beginning of the generated code + for a lexical block. */ + +static void +dwarfout_begin_block (line, blocknum) + unsigned int line ATTRIBUTE_UNUSED; + unsigned int blocknum; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + function_section (current_function_decl); + sprintf (label, BLOCK_BEGIN_LABEL_FMT, blocknum); + ASM_OUTPUT_LABEL (asm_out_file, label); +} + +/* Output a marker (i.e. a label) for the end of the generated code + for a lexical block. */ + +static void +dwarfout_end_block (line, blocknum) + unsigned int line ATTRIBUTE_UNUSED; + unsigned int blocknum; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + function_section (current_function_decl); + sprintf (label, BLOCK_END_LABEL_FMT, blocknum); + ASM_OUTPUT_LABEL (asm_out_file, label); +} + +/* Output a marker (i.e. a label) for the point in the generated code where + the real body of the function begins (after parameters have been moved + to their home locations). */ + +static void +dwarfout_end_prologue (line, file) + unsigned int line ATTRIBUTE_UNUSED; + const char *file ATTRIBUTE_UNUSED; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (! use_gnu_debug_info_extensions) + return; + + function_section (current_function_decl); + sprintf (label, BODY_BEGIN_LABEL_FMT, current_function_funcdef_no); + ASM_OUTPUT_LABEL (asm_out_file, label); +} + +/* Output a marker (i.e. a label) for the point in the generated code where + the real body of the function ends (just before the epilogue code). */ + +static void +dwarfout_end_function (line) + unsigned int line ATTRIBUTE_UNUSED; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (! use_gnu_debug_info_extensions) + return; + function_section (current_function_decl); + sprintf (label, BODY_END_LABEL_FMT, current_function_funcdef_no); + ASM_OUTPUT_LABEL (asm_out_file, label); +} + +/* Output a marker (i.e. a label) for the absolute end of the generated code + for a function definition. This gets called *after* the epilogue code + has been generated. */ + +static void +dwarfout_end_epilogue (line, file) + unsigned int line ATTRIBUTE_UNUSED; + const char *file ATTRIBUTE_UNUSED; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + /* Output a label to mark the endpoint of the code generated for this + function. */ + + sprintf (label, FUNC_END_LABEL_FMT, current_function_funcdef_no); + ASM_OUTPUT_LABEL (asm_out_file, label); +} + +static void +shuffle_filename_entry (new_zeroth) + filename_entry *new_zeroth; +{ + filename_entry temp_entry; + filename_entry *limit_p; + filename_entry *move_p; + + if (new_zeroth == &filename_table[0]) + return; + + temp_entry = *new_zeroth; + + /* Shift entries up in the table to make room at [0]. */ + + limit_p = &filename_table[0]; + for (move_p = new_zeroth; move_p > limit_p; move_p--) + *move_p = *(move_p-1); + + /* Install the found entry at [0]. */ + + filename_table[0] = temp_entry; +} + +/* Create a new (string) entry for the .debug_sfnames section. */ + +static void +generate_new_sfname_entry () +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SFNAMES_SECTION); + sprintf (label, SFNAMES_ENTRY_LABEL_FMT, filename_table[0].number); + ASM_OUTPUT_LABEL (asm_out_file, label); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, + filename_table[0].name + ? filename_table[0].name + : ""); + ASM_OUTPUT_POP_SECTION (asm_out_file); +} + +/* Lookup a filename (in the list of filenames that we know about here in + dwarfout.c) and return its "index". The index of each (known) filename + is just a unique number which is associated with only that one filename. + We need such numbers for the sake of generating labels (in the + .debug_sfnames section) and references to those unique labels (in the + .debug_srcinfo and .debug_macinfo sections). + + If the filename given as an argument is not found in our current list, + add it to the list and assign it the next available unique index number. + + Whatever we do (i.e. whether we find a pre-existing filename or add a new + one), we shuffle the filename found (or added) up to the zeroth entry of + our list of filenames (which is always searched linearly). We do this so + as to optimize the most common case for these filename lookups within + dwarfout.c. The most common case by far is the case where we call + lookup_filename to lookup the very same filename that we did a lookup + on the last time we called lookup_filename. We make sure that this + common case is fast because such cases will constitute 99.9% of the + lookups we ever do (in practice). + + If we add a new filename entry to our table, we go ahead and generate + the corresponding entry in the .debug_sfnames section right away. + Doing so allows us to avoid tickling an assembler bug (present in some + m68k assemblers) which yields assembly-time errors in cases where the + difference of two label addresses is taken and where the two labels + are in a section *other* than the one where the difference is being + calculated, and where at least one of the two symbol references is a + forward reference. (This bug could be tickled by our .debug_srcinfo + entries if we don't output their corresponding .debug_sfnames entries + before them.) */ + +static unsigned +lookup_filename (file_name) + const char *file_name; +{ + filename_entry *search_p; + filename_entry *limit_p = &filename_table[ft_entries]; + + for (search_p = filename_table; search_p < limit_p; search_p++) + if (!strcmp (file_name, search_p->name)) + { + /* When we get here, we have found the filename that we were + looking for in the filename_table. Now we want to make sure + that it gets moved to the zero'th entry in the table (if it + is not already there) so that subsequent attempts to find the + same filename will find it as quickly as possible. */ + + shuffle_filename_entry (search_p); + return filename_table[0].number; + } + + /* We come here whenever we have a new filename which is not registered + in the current table. Here we add it to the table. */ + + /* Prepare to add a new table entry by making sure there is enough space + in the table to do so. If not, expand the current table. */ + + if (ft_entries == ft_entries_allocated) + { + ft_entries_allocated += FT_ENTRIES_INCREMENT; + filename_table + = (filename_entry *) + xrealloc (filename_table, + ft_entries_allocated * sizeof (filename_entry)); + } + + /* Initially, add the new entry at the end of the filename table. */ + + filename_table[ft_entries].number = ft_entries; + filename_table[ft_entries].name = xstrdup (file_name); + + /* Shuffle the new entry into filename_table[0]. */ + + shuffle_filename_entry (&filename_table[ft_entries]); + + if (debug_info_level >= DINFO_LEVEL_NORMAL) + generate_new_sfname_entry (); + + ft_entries++; + return filename_table[0].number; +} + +static void +generate_srcinfo_entry (line_entry_num, files_entry_num) + unsigned line_entry_num; + unsigned files_entry_num; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SRCINFO_SECTION); + sprintf (label, LINE_ENTRY_LABEL_FMT, line_entry_num); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, label, LINE_BEGIN_LABEL); + sprintf (label, SFNAMES_ENTRY_LABEL_FMT, files_entry_num); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, label, SFNAMES_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); +} + +static void +dwarfout_source_line (line, filename) + unsigned int line; + const char *filename; +{ + if (debug_info_level >= DINFO_LEVEL_NORMAL + /* We can't emit line number info for functions in separate sections, + because the assembler can't subtract labels in different sections. */ + && DECL_SECTION_NAME (current_function_decl) == NULL_TREE) + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + static unsigned last_line_entry_num = 0; + static unsigned prev_file_entry_num = (unsigned) -1; + unsigned this_file_entry_num; + + function_section (current_function_decl); + sprintf (label, LINE_CODE_LABEL_FMT, ++last_line_entry_num); + ASM_OUTPUT_LABEL (asm_out_file, label); + + fputc ('\n', asm_out_file); + + if (use_gnu_debug_info_extensions) + this_file_entry_num = lookup_filename (filename); + else + this_file_entry_num = (unsigned) -1; + + ASM_OUTPUT_PUSH_SECTION (asm_out_file, LINE_SECTION); + if (this_file_entry_num != prev_file_entry_num) + { + char line_entry_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + sprintf (line_entry_label, LINE_ENTRY_LABEL_FMT, last_line_entry_num); + ASM_OUTPUT_LABEL (asm_out_file, line_entry_label); + } + + { + const char *tail = strrchr (filename, '/'); + + if (tail != NULL) + filename = tail; + } + + dw2_asm_output_data (4, line, "%s:%u", filename, line); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, 0xffff); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, label, TEXT_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + + if (this_file_entry_num != prev_file_entry_num) + generate_srcinfo_entry (last_line_entry_num, this_file_entry_num); + prev_file_entry_num = this_file_entry_num; + } +} + +/* Generate an entry in the .debug_macinfo section. */ + +static void +generate_macinfo_entry (type, offset, string) + unsigned int type; + rtx offset; + const char *string; +{ + if (! use_gnu_debug_info_extensions) + return; + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_MACINFO_SECTION); + assemble_integer (gen_rtx_PLUS (SImode, GEN_INT (type << 24), offset), + 4, BITS_PER_UNIT, 1); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, string); + ASM_OUTPUT_POP_SECTION (asm_out_file); +} + +/* Wrapper for toplev.c callback to check debug info level. */ +static void +dwarfout_start_source_file_check (line, filename) + unsigned int line; + const char *filename; +{ + if (debug_info_level == DINFO_LEVEL_VERBOSE) + dwarfout_start_source_file (line, filename); +} + +static void +dwarfout_start_source_file (line, filename) + unsigned int line ATTRIBUTE_UNUSED; + const char *filename; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + const char *label1, *label2; + + sprintf (label, SFNAMES_ENTRY_LABEL_FMT, lookup_filename (filename)); + label1 = (*label == '*') + label; + label2 = (*SFNAMES_BEGIN_LABEL == '*') + SFNAMES_BEGIN_LABEL; + generate_macinfo_entry (MACINFO_start, + gen_rtx_MINUS (Pmode, + gen_rtx_SYMBOL_REF (Pmode, label1), + gen_rtx_SYMBOL_REF (Pmode, label2)), + ""); +} + +/* Wrapper for toplev.c callback to check debug info level. */ +static void +dwarfout_end_source_file_check (lineno) + unsigned lineno; +{ + if (debug_info_level == DINFO_LEVEL_VERBOSE) + dwarfout_end_source_file (lineno); +} + +static void +dwarfout_end_source_file (lineno) + unsigned lineno; +{ + generate_macinfo_entry (MACINFO_resume, GEN_INT (lineno), ""); +} + +/* Called from check_newline in c-parse.y. The `buffer' parameter + contains the tail part of the directive line, i.e. the part which + is past the initial whitespace, #, whitespace, directive-name, + whitespace part. */ + +static void +dwarfout_define (lineno, buffer) + unsigned lineno; + const char *buffer; +{ + static int initialized = 0; + + if (!initialized) + { + dwarfout_start_source_file (0, primary_filename); + initialized = 1; + } + generate_macinfo_entry (MACINFO_define, GEN_INT (lineno), buffer); +} + +/* Called from check_newline in c-parse.y. The `buffer' parameter + contains the tail part of the directive line, i.e. the part which + is past the initial whitespace, #, whitespace, directive-name, + whitespace part. */ + +static void +dwarfout_undef (lineno, buffer) + unsigned lineno; + const char *buffer; +{ + generate_macinfo_entry (MACINFO_undef, GEN_INT (lineno), buffer); +} + +/* Set up for Dwarf output at the start of compilation. */ + +static void +dwarfout_init (main_input_filename) + const char *main_input_filename; +{ + warning ("support for the DWARF1 debugging format is deprecated"); + + /* Remember the name of the primary input file. */ + + primary_filename = main_input_filename; + + /* Allocate the initial hunk of the pending_sibling_stack. */ + + pending_sibling_stack + = (unsigned *) + xmalloc (PENDING_SIBLINGS_INCREMENT * sizeof (unsigned)); + pending_siblings_allocated = PENDING_SIBLINGS_INCREMENT; + pending_siblings = 1; + + /* Allocate the initial hunk of the filename_table. */ + + filename_table + = (filename_entry *) + xmalloc (FT_ENTRIES_INCREMENT * sizeof (filename_entry)); + ft_entries_allocated = FT_ENTRIES_INCREMENT; + ft_entries = 0; + + /* Allocate the initial hunk of the pending_types_list. */ + + pending_types_list + = (tree *) xmalloc (PENDING_TYPES_INCREMENT * sizeof (tree)); + pending_types_allocated = PENDING_TYPES_INCREMENT; + pending_types = 0; + + /* Create an artificial RECORD_TYPE node which we can use in our hack + to get the DIEs representing types of formal parameters to come out + only *after* the DIEs for the formal parameters themselves. */ + + fake_containing_scope = make_node (RECORD_TYPE); + + /* Output a starting label for the .text section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, TEXT_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, TEXT_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + + /* Output a starting label for the .data section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DATA_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, DATA_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + +#if 0 /* GNU C doesn't currently use .data1. */ + /* Output a starting label for the .data1 section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DATA1_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, DATA1_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); +#endif + + /* Output a starting label for the .rodata section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, RODATA_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, RODATA_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + +#if 0 /* GNU C doesn't currently use .rodata1. */ + /* Output a starting label for the .rodata1 section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, RODATA1_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, RODATA1_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); +#endif + + /* Output a starting label for the .bss section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, BSS_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, BSS_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + + if (debug_info_level >= DINFO_LEVEL_NORMAL) + { + if (use_gnu_debug_info_extensions) + { + /* Output a starting label and an initial (compilation directory) + entry for the .debug_sfnames section. The starting label will be + referenced by the initial entry in the .debug_srcinfo section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SFNAMES_SECTION); + ASM_OUTPUT_LABEL (asm_out_file, SFNAMES_BEGIN_LABEL); + { + const char *pwd = getpwd (); + char *dirname; + + if (!pwd) + fatal_io_error ("can't get current directory"); + + dirname = concat (pwd, "/", NULL); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, dirname); + free (dirname); + } + ASM_OUTPUT_POP_SECTION (asm_out_file); + } + + if (debug_info_level >= DINFO_LEVEL_VERBOSE + && use_gnu_debug_info_extensions) + { + /* Output a starting label for the .debug_macinfo section. This + label will be referenced by the AT_mac_info attribute in the + TAG_compile_unit DIE. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_MACINFO_SECTION); + ASM_OUTPUT_LABEL (asm_out_file, MACINFO_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + } + + /* Generate the initial entry for the .line section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, LINE_SECTION); + ASM_OUTPUT_LABEL (asm_out_file, LINE_BEGIN_LABEL); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, LINE_END_LABEL, LINE_BEGIN_LABEL); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + + if (use_gnu_debug_info_extensions) + { + /* Generate the initial entry for the .debug_srcinfo section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SRCINFO_SECTION); + ASM_OUTPUT_LABEL (asm_out_file, SRCINFO_BEGIN_LABEL); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, LINE_BEGIN_LABEL); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, SFNAMES_BEGIN_LABEL); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_END_LABEL); +#ifdef DWARF_TIMESTAMPS + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, time (NULL)); +#else + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1); +#endif + ASM_OUTPUT_POP_SECTION (asm_out_file); + } + + /* Generate the initial entry for the .debug_pubnames section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_PUBNAMES_SECTION); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, DEBUG_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + + /* Generate the initial entry for the .debug_aranges section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_ARANGES_SECTION); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, + DEBUG_ARANGES_END_LABEL, + DEBUG_ARANGES_BEGIN_LABEL); + ASM_OUTPUT_LABEL (asm_out_file, DEBUG_ARANGES_BEGIN_LABEL); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 1); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, DEBUG_BEGIN_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + } + + /* Setup first DIE number == 1. */ + NEXT_DIE_NUM = next_unused_dienum++; + + /* Generate the initial DIE for the .debug section. Note that the + (string) value given in the AT_name attribute of the TAG_compile_unit + DIE will (typically) be a relative pathname and that this pathname + should be taken as being relative to the directory from which the + compiler was invoked when the given (base) source file was compiled. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SECTION); + ASM_OUTPUT_LABEL (asm_out_file, DEBUG_BEGIN_LABEL); + output_die (output_compile_unit_die, (PTR) main_input_filename); + ASM_OUTPUT_POP_SECTION (asm_out_file); + + fputc ('\n', asm_out_file); +} + +/* Output stuff that dwarf requires at the end of every file. */ + +static void +dwarfout_finish (main_input_filename) + const char *main_input_filename ATTRIBUTE_UNUSED; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SECTION); + retry_incomplete_types (); + fputc ('\n', asm_out_file); + + /* Mark the end of the chain of siblings which represent all file-scope + declarations in this compilation unit. */ + + /* The (null) DIE which represents the terminator for the (sibling linked) + list of file-scope items is *special*. Normally, we would just call + end_sibling_chain at this point in order to output a word with the + value `4' and that word would act as the terminator for the list of + DIEs describing file-scope items. Unfortunately, if we were to simply + do that, the label that would follow this DIE in the .debug section + (i.e. `..D2') would *not* be properly aligned (as it must be on some + machines) to a 4 byte boundary. + + In order to force the label `..D2' to get aligned to a 4 byte boundary, + the trick used is to insert extra (otherwise useless) padding bytes + into the (null) DIE that we know must precede the ..D2 label in the + .debug section. The amount of padding required can be anywhere between + 0 and 3 bytes. The length word at the start of this DIE (i.e. the one + with the padding) would normally contain the value 4, but now it will + also have to include the padding bytes, so it will instead have some + value in the range 4..7. + + Fortunately, the rules of Dwarf say that any DIE whose length word + contains *any* value less than 8 should be treated as a null DIE, so + this trick works out nicely. Clever, eh? Don't give me any credit + (or blame). I didn't think of this scheme. I just conformed to it. + */ + + output_die (output_padded_null_die, (void *) 0); + dienum_pop (); + + sprintf (label, DIE_BEGIN_LABEL_FMT, NEXT_DIE_NUM); + ASM_OUTPUT_LABEL (asm_out_file, label); /* should be ..D2 */ + ASM_OUTPUT_POP_SECTION (asm_out_file); + + /* Output a terminator label for the .text section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, TEXT_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, TEXT_END_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + + /* Output a terminator label for the .data section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DATA_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, DATA_END_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + +#if 0 /* GNU C doesn't currently use .data1. */ + /* Output a terminator label for the .data1 section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DATA1_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, DATA1_END_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); +#endif + + /* Output a terminator label for the .rodata section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, RODATA_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, RODATA_END_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + +#if 0 /* GNU C doesn't currently use .rodata1. */ + /* Output a terminator label for the .rodata1 section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, RODATA1_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, RODATA1_END_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); +#endif + + /* Output a terminator label for the .bss section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, BSS_SECTION_NAME); + ASM_OUTPUT_LABEL (asm_out_file, BSS_END_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + + if (debug_info_level >= DINFO_LEVEL_NORMAL) + { + /* Output a terminating entry for the .line section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, LINE_SECTION); + ASM_OUTPUT_LABEL (asm_out_file, LINE_LAST_ENTRY_LABEL); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, 0xffff); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, TEXT_END_LABEL, TEXT_BEGIN_LABEL); + ASM_OUTPUT_LABEL (asm_out_file, LINE_END_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + + if (use_gnu_debug_info_extensions) + { + /* Output a terminating entry for the .debug_srcinfo section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SRCINFO_SECTION); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, + LINE_LAST_ENTRY_LABEL, LINE_BEGIN_LABEL); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1); + ASM_OUTPUT_POP_SECTION (asm_out_file); + } + + if (debug_info_level >= DINFO_LEVEL_VERBOSE) + { + /* Output terminating entries for the .debug_macinfo section. */ + + dwarfout_end_source_file (0); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_MACINFO_SECTION); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, ""); + ASM_OUTPUT_POP_SECTION (asm_out_file); + } + + /* Generate the terminating entry for the .debug_pubnames section. */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_PUBNAMES_SECTION); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, ""); + ASM_OUTPUT_POP_SECTION (asm_out_file); + + /* Generate the terminating entries for the .debug_aranges section. + + Note that we want to do this only *after* we have output the end + labels (for the various program sections) which we are going to + refer to here. This allows us to work around a bug in the m68k + svr4 assembler. That assembler gives bogus assembly-time errors + if (within any given section) you try to take the difference of + two relocatable symbols, both of which are located within some + other section, and if one (or both?) of the symbols involved is + being forward-referenced. By generating the .debug_aranges + entries at this late point in the assembly output, we skirt the + issue simply by avoiding forward-references. + */ + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_ARANGES_SECTION); + + ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, TEXT_END_LABEL, TEXT_BEGIN_LABEL); + + ASM_OUTPUT_DWARF_ADDR (asm_out_file, DATA_BEGIN_LABEL); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, DATA_END_LABEL, DATA_BEGIN_LABEL); + +#if 0 /* GNU C doesn't currently use .data1. */ + ASM_OUTPUT_DWARF_ADDR (asm_out_file, DATA1_BEGIN_LABEL); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, DATA1_END_LABEL, + DATA1_BEGIN_LABEL); +#endif + + ASM_OUTPUT_DWARF_ADDR (asm_out_file, RODATA_BEGIN_LABEL); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, RODATA_END_LABEL, + RODATA_BEGIN_LABEL); + +#if 0 /* GNU C doesn't currently use .rodata1. */ + ASM_OUTPUT_DWARF_ADDR (asm_out_file, RODATA1_BEGIN_LABEL); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, RODATA1_END_LABEL, + RODATA1_BEGIN_LABEL); +#endif + + ASM_OUTPUT_DWARF_ADDR (asm_out_file, BSS_BEGIN_LABEL); + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, BSS_END_LABEL, BSS_BEGIN_LABEL); + + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); + + ASM_OUTPUT_LABEL (asm_out_file, DEBUG_ARANGES_END_LABEL); + ASM_OUTPUT_POP_SECTION (asm_out_file); + } + + /* There should not be any pending types left at the end. We need + this now because it may not have been checked on the last call to + dwarfout_file_scope_decl. */ + if (pending_types != 0) + abort (); +} + +#endif /* DWARF_DEBUGGING_INFO */ diff --git a/contrib/gcc/emit-rtl.c b/contrib/gcc/emit-rtl.c index 9607bf6..9df2d6c 100644 --- a/contrib/gcc/emit-rtl.c +++ b/contrib/gcc/emit-rtl.c @@ -1,7 +1,6 @@ /* Emit RTL for the GCC expander. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -17,22 +16,24 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ /* Middle-to-low level generation of rtx code and insns. - This file contains support functions for creating rtl expressions - and manipulating them in the doubly-linked chain of insns. + This file contains the functions `gen_rtx', `gen_reg_rtx' + and `gen_label_rtx' that are the usual ways of creating rtl + expressions for most purposes. + + It also has the functions for creating insns and linking + them in the doubly-linked chain. The patterns of the insns are created by machine-dependent routines in insn-emit.c, which is generated automatically from - the machine description. These routines make the individual rtx's - of the pattern with `gen_rtx_fmt_ee' and others in genrtl.[ch], - which are automatically generated from rtl.def; what is machine - dependent is the kind of rtx's they make and what arguments they - use. */ + the machine description. These routines use `gen_rtx' to make + the individual rtx's of the pattern; what is machine dependent + is the kind of rtx's they make and what arguments they use. */ #include "config.h" #include "system.h" @@ -56,7 +57,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "ggc.h" #include "debug.h" #include "langhooks.h" -#include "tree-pass.h" /* Commonly used modes. */ @@ -71,6 +71,17 @@ enum machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */ static GTY(()) int label_num = 1; +/* Highest label number in current function. + Zero means use the value of label_num instead. + This is nonzero only when belatedly compiling an inline function. */ + +static int last_label_num; + +/* Value label_num had when set_new_last_label_num was called. + If label_num has not changed since then, last_label_num is valid. */ + +static int base_label_num; + /* Nonzero means do not generate NOTEs for source line numbers. */ static int no_line_numbers; @@ -165,6 +176,7 @@ static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def))) #define last_location (cfun->emit->x_last_location) #define first_label_num (cfun->emit->x_first_label_num) +static rtx make_jump_insn_raw (rtx); static rtx make_call_insn_raw (rtx); static rtx find_line_note (rtx); static rtx change_address_1 (rtx, enum machine_mode, rtx, int); @@ -184,7 +196,8 @@ static hashval_t reg_attrs_htab_hash (const void *); static int reg_attrs_htab_eq (const void *, const void *); static reg_attrs *get_reg_attrs (tree, int); static tree component_ref_for_mem_expr (tree); -static rtx gen_const_vector (enum machine_mode, int); +static rtx gen_const_vector_0 (enum machine_mode); +static rtx gen_complex_constant_part (enum machine_mode, rtx, int); static void copy_rtx_if_shared_1 (rtx *orig); /* Probability of the conditional branch currently proceeded by try_split. @@ -254,7 +267,7 @@ mem_attrs_htab_hash (const void *x) return (p->alias ^ (p->align * 1000) ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000) ^ ((p->size ? INTVAL (p->size) : 0) * 2500000) - ^ (size_t) iterative_hash_expr (p->expr, 0)); + ^ (size_t) p->expr); } /* Returns nonzero if the value represented by X (which is really a @@ -267,11 +280,8 @@ mem_attrs_htab_eq (const void *x, const void *y) mem_attrs *p = (mem_attrs *) x; mem_attrs *q = (mem_attrs *) y; - return (p->alias == q->alias && p->offset == q->offset - && p->size == q->size && p->align == q->align - && (p->expr == q->expr - || (p->expr != NULL_TREE && q->expr != NULL_TREE - && operand_equal_p (p->expr, q->expr, 0)))); + return (p->alias == q->alias && p->expr == q->expr && p->offset == q->offset + && p->size == q->size && p->align == q->align); } /* Allocate a new mem_attrs structure and insert it into the hash table if @@ -429,7 +439,7 @@ const_double_from_real_value (REAL_VALUE_TYPE value, enum machine_mode mode) rtx real = rtx_alloc (CONST_DOUBLE); PUT_MODE (real, mode); - real->u.rv = value; + memcpy (&CONST_DOUBLE_LOW (real), &value, sizeof (REAL_VALUE_TYPE)); return lookup_const_double (real); } @@ -445,28 +455,64 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode) rtx value; unsigned int i; - /* There are the following cases (note that there are no modes with - HOST_BITS_PER_WIDE_INT < GET_MODE_BITSIZE (mode) < 2 * HOST_BITS_PER_WIDE_INT): - - 1) If GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT, then we use - gen_int_mode. - 2) GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT, but the value of - the integer fits into HOST_WIDE_INT anyway (i.e., i1 consists only - from copies of the sign bit, and sign of i0 and i1 are the same), then - we return a CONST_INT for i0. - 3) Otherwise, we create a CONST_DOUBLE for i0 and i1. */ if (mode != VOIDmode) { - gcc_assert (GET_MODE_CLASS (mode) == MODE_INT - || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT - /* We can get a 0 for an error mark. */ - || GET_MODE_CLASS (mode) == MODE_VECTOR_INT - || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT); - - if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) - return gen_int_mode (i0, mode); - - gcc_assert (GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT); + int width; + if (GET_MODE_CLASS (mode) != MODE_INT + && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT + /* We can get a 0 for an error mark. */ + && GET_MODE_CLASS (mode) != MODE_VECTOR_INT + && GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT) + abort (); + + /* We clear out all bits that don't belong in MODE, unless they and + our sign bit are all one. So we get either a reasonable negative + value or a reasonable unsigned value for this mode. */ + width = GET_MODE_BITSIZE (mode); + if (width < HOST_BITS_PER_WIDE_INT + && ((i0 & ((HOST_WIDE_INT) (-1) << (width - 1))) + != ((HOST_WIDE_INT) (-1) << (width - 1)))) + i0 &= ((HOST_WIDE_INT) 1 << width) - 1, i1 = 0; + else if (width == HOST_BITS_PER_WIDE_INT + && ! (i1 == ~0 && i0 < 0)) + i1 = 0; + else if (width > 2 * HOST_BITS_PER_WIDE_INT) + /* We cannot represent this value as a constant. */ + abort (); + + /* If this would be an entire word for the target, but is not for + the host, then sign-extend on the host so that the number will + look the same way on the host that it would on the target. + + For example, when building a 64 bit alpha hosted 32 bit sparc + targeted compiler, then we want the 32 bit unsigned value -1 to be + represented as a 64 bit value -1, and not as 0x00000000ffffffff. + The latter confuses the sparc backend. */ + + if (width < HOST_BITS_PER_WIDE_INT + && (i0 & ((HOST_WIDE_INT) 1 << (width - 1)))) + i0 |= ((HOST_WIDE_INT) (-1) << width); + + /* If MODE fits within HOST_BITS_PER_WIDE_INT, always use a + CONST_INT. + + ??? Strictly speaking, this is wrong if we create a CONST_INT for + a large unsigned constant with the size of MODE being + HOST_BITS_PER_WIDE_INT and later try to interpret that constant + in a wider mode. In that case we will mis-interpret it as a + negative number. + + Unfortunately, the only alternative is to make a CONST_DOUBLE for + any constant in any mode if it is an unsigned constant larger + than the maximum signed integer in an int on the host. However, + doing this will break everyone that always expects to see a + CONST_INT for SImode and smaller. + + We have always been making CONST_INTs in this case, so nothing + new is being broken. */ + + if (width <= HOST_BITS_PER_WIDE_INT) + i1 = (i0 < 0) ? ~(HOST_WIDE_INT) 0 : 0; } /* If this integer fits in one word, return a CONST_INT. */ @@ -563,152 +609,153 @@ gen_rtx_MEM (enum machine_mode mode, rtx addr) return rt; } -/* Generate a memory referring to non-trapping constant memory. */ - rtx -gen_const_mem (enum machine_mode mode, rtx addr) +gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset) { - rtx mem = gen_rtx_MEM (mode, addr); - MEM_READONLY_P (mem) = 1; - MEM_NOTRAP_P (mem) = 1; - return mem; + /* This is the most common failure type. + Catch it early so we can see who does it. */ + if ((offset % GET_MODE_SIZE (mode)) != 0) + abort (); + + /* This check isn't usable right now because combine will + throw arbitrary crap like a CALL into a SUBREG in + gen_lowpart_for_combine so we must just eat it. */ +#if 0 + /* Check for this too. */ + if (offset >= GET_MODE_SIZE (GET_MODE (reg))) + abort (); +#endif + return gen_rtx_raw_SUBREG (mode, reg, offset); } -/* Generate a MEM referring to fixed portions of the frame, e.g., register - save areas. */ +/* Generate a SUBREG representing the least-significant part of REG if MODE + is smaller than mode of REG, otherwise paradoxical SUBREG. */ rtx -gen_frame_mem (enum machine_mode mode, rtx addr) +gen_lowpart_SUBREG (enum machine_mode mode, rtx reg) { - rtx mem = gen_rtx_MEM (mode, addr); - MEM_NOTRAP_P (mem) = 1; - set_mem_alias_set (mem, get_frame_alias_set ()); - return mem; + enum machine_mode inmode; + + inmode = GET_MODE (reg); + if (inmode == VOIDmode) + inmode = mode; + return gen_rtx_SUBREG (mode, reg, + subreg_lowpart_offset (mode, inmode)); } + +/* rtx gen_rtx (code, mode, [element1, ..., elementn]) +** +** This routine generates an RTX of the size specified by +** <code>, which is an RTX code. The RTX structure is initialized +** from the arguments <element1> through <elementn>, which are +** interpreted according to the specific RTX type's format. The +** special machine mode associated with the rtx (if any) is specified +** in <mode>. +** +** gen_rtx can be invoked in a way which resembles the lisp-like +** rtx it will generate. For example, the following rtx structure: +** +** (plus:QI (mem:QI (reg:SI 1)) +** (mem:QI (plusw:SI (reg:SI 2) (reg:SI 3)))) +** +** ...would be generated by the following C code: +** +** gen_rtx (PLUS, QImode, +** gen_rtx (MEM, QImode, +** gen_rtx (REG, SImode, 1)), +** gen_rtx (MEM, QImode, +** gen_rtx (PLUS, SImode, +** gen_rtx (REG, SImode, 2), +** gen_rtx (REG, SImode, 3)))), +*/ -/* Generate a MEM referring to a temporary use of the stack, not part - of the fixed stack frame. For example, something which is pushed - by a target splitter. */ +/*VARARGS2*/ rtx -gen_tmp_stack_mem (enum machine_mode mode, rtx addr) +gen_rtx (enum rtx_code code, enum machine_mode mode, ...) { - rtx mem = gen_rtx_MEM (mode, addr); - MEM_NOTRAP_P (mem) = 1; - if (!current_function_calls_alloca) - set_mem_alias_set (mem, get_frame_alias_set ()); - return mem; -} + int i; /* Array indices... */ + const char *fmt; /* Current rtx's format... */ + rtx rt_val; /* RTX to return to caller... */ + va_list p; -/* We want to create (subreg:OMODE (obj:IMODE) OFFSET). Return true if - this construct would be valid, and false otherwise. */ + va_start (p, mode); -bool -validate_subreg (enum machine_mode omode, enum machine_mode imode, - rtx reg, unsigned int offset) -{ - unsigned int isize = GET_MODE_SIZE (imode); - unsigned int osize = GET_MODE_SIZE (omode); + switch (code) + { + case CONST_INT: + rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT)); + break; - /* All subregs must be aligned. */ - if (offset % osize != 0) - return false; + case CONST_DOUBLE: + { + HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT); + HOST_WIDE_INT arg1 = va_arg (p, HOST_WIDE_INT); - /* The subreg offset cannot be outside the inner object. */ - if (offset >= isize) - return false; + rt_val = immed_double_const (arg0, arg1, mode); + } + break; - /* ??? This should not be here. Temporarily continue to allow word_mode - subregs of anything. The most common offender is (subreg:SI (reg:DF)). - Generally, backends are doing something sketchy but it'll take time to - fix them all. */ - if (omode == word_mode) - ; - /* ??? Similarly, e.g. with (subreg:DF (reg:TI)). Though store_bit_field - is the culprit here, and not the backends. */ - else if (osize >= UNITS_PER_WORD && isize >= osize) - ; - /* Allow component subregs of complex and vector. Though given the below - extraction rules, it's not always clear what that means. */ - else if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode)) - && GET_MODE_INNER (imode) == omode) - ; - /* ??? x86 sse code makes heavy use of *paradoxical* vector subregs, - i.e. (subreg:V4SF (reg:SF) 0). This surely isn't the cleanest way to - represent this. It's questionable if this ought to be represented at - all -- why can't this all be hidden in post-reload splitters that make - arbitrarily mode changes to the registers themselves. */ - else if (VECTOR_MODE_P (omode) && GET_MODE_INNER (omode) == imode) - ; - /* Subregs involving floating point modes are not allowed to - change size. Therefore (subreg:DI (reg:DF) 0) is fine, but - (subreg:SI (reg:DF) 0) isn't. */ - else if (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode)) - { - if (isize != osize) - return false; - } + case REG: + rt_val = gen_rtx_REG (mode, va_arg (p, int)); + break; - /* Paradoxical subregs must have offset zero. */ - if (osize > isize) - return offset == 0; + case MEM: + rt_val = gen_rtx_MEM (mode, va_arg (p, rtx)); + break; - /* This is a normal subreg. Verify that the offset is representable. */ + default: + rt_val = rtx_alloc (code); /* Allocate the storage space. */ + rt_val->mode = mode; /* Store the machine mode... */ - /* For hard registers, we already have most of these rules collected in - subreg_offset_representable_p. */ - if (reg && REG_P (reg) && HARD_REGISTER_P (reg)) - { - unsigned int regno = REGNO (reg); + fmt = GET_RTX_FORMAT (code); /* Find the right format... */ + for (i = 0; i < GET_RTX_LENGTH (code); i++) + { + switch (*fmt++) + { + case '0': /* Field with unknown use. Zero it. */ + X0EXP (rt_val, i) = NULL_RTX; + break; -#ifdef CANNOT_CHANGE_MODE_CLASS - if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode)) - && GET_MODE_INNER (imode) == omode) - ; - else if (REG_CANNOT_CHANGE_MODE_P (regno, imode, omode)) - return false; -#endif + case 'i': /* An integer? */ + XINT (rt_val, i) = va_arg (p, int); + break; - return subreg_offset_representable_p (regno, imode, offset, omode); - } + case 'w': /* A wide integer? */ + XWINT (rt_val, i) = va_arg (p, HOST_WIDE_INT); + break; - /* For pseudo registers, we want most of the same checks. Namely: - If the register no larger than a word, the subreg must be lowpart. - If the register is larger than a word, the subreg must be the lowpart - of a subword. A subreg does *not* perform arbitrary bit extraction. - Given that we've already checked mode/offset alignment, we only have - to check subword subregs here. */ - if (osize < UNITS_PER_WORD) - { - enum machine_mode wmode = isize > UNITS_PER_WORD ? word_mode : imode; - unsigned int low_off = subreg_lowpart_offset (omode, wmode); - if (offset % UNITS_PER_WORD != low_off) - return false; - } - return true; -} + case 's': /* A string? */ + XSTR (rt_val, i) = va_arg (p, char *); + break; -rtx -gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset) -{ - gcc_assert (validate_subreg (mode, GET_MODE (reg), reg, offset)); - return gen_rtx_raw_SUBREG (mode, reg, offset); -} + case 'e': /* An expression? */ + case 'u': /* An insn? Same except when printing. */ + XEXP (rt_val, i) = va_arg (p, rtx); + break; -/* Generate a SUBREG representing the least-significant part of REG if MODE - is smaller than mode of REG, otherwise paradoxical SUBREG. */ + case 'E': /* An RTX vector? */ + XVEC (rt_val, i) = va_arg (p, rtvec); + break; -rtx -gen_lowpart_SUBREG (enum machine_mode mode, rtx reg) -{ - enum machine_mode inmode; + case 'b': /* A bitmap? */ + XBITMAP (rt_val, i) = va_arg (p, bitmap); + break; - inmode = GET_MODE (reg); - if (inmode == VOIDmode) - inmode = mode; - return gen_rtx_SUBREG (mode, reg, - subreg_lowpart_offset (mode, inmode)); + case 't': /* A tree? */ + XTREE (rt_val, i) = va_arg (p, tree); + break; + + default: + abort (); + } + } + break; + } + + va_end (p); + return rt_val; } - + /* gen_rtvec (n, [rt1, ..., rtn]) ** ** This routine creates an rtvec and stores within it the @@ -768,7 +815,8 @@ gen_reg_rtx (enum machine_mode mode) /* Don't let anything called after initial flow analysis create new registers. */ - gcc_assert (!no_new_pseudos); + if (no_new_pseudos) + abort (); if (generating_concat_p && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT @@ -813,96 +861,13 @@ gen_reg_rtx (enum machine_mode mode) return val; } -/* Generate a register with same attributes as REG, but offsetted by OFFSET. - Do the big endian correction if needed. */ +/* Generate a register with same attributes as REG, + but offsetted by OFFSET. */ rtx gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, int offset) { rtx new = gen_rtx_REG (mode, regno); - tree decl; - HOST_WIDE_INT var_size; - - /* PR middle-end/14084 - The problem appears when a variable is stored in a larger register - and later it is used in the original mode or some mode in between - or some part of variable is accessed. - - On little endian machines there is no problem because - the REG_OFFSET of the start of the variable is the same when - accessed in any mode (it is 0). - - However, this is not true on big endian machines. - The offset of the start of the variable is different when accessed - in different modes. - When we are taking a part of the REG we have to change the OFFSET - from offset WRT size of mode of REG to offset WRT size of variable. - - If we would not do the big endian correction the resulting REG_OFFSET - would be larger than the size of the DECL. - - Examples of correction, for BYTES_BIG_ENDIAN WORDS_BIG_ENDIAN machine: - - REG.mode MODE DECL size old offset new offset description - DI SI 4 4 0 int32 in SImode - DI SI 1 4 0 char in SImode - DI QI 1 7 0 char in QImode - DI QI 4 5 1 1st element in QImode - of char[4] - DI HI 4 6 2 1st element in HImode - of int16[2] - - If the size of DECL is equal or greater than the size of REG - we can't do this correction because the register holds the - whole variable or a part of the variable and thus the REG_OFFSET - is already correct. */ - - decl = REG_EXPR (reg); - if ((BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN) - && decl != NULL - && offset > 0 - && GET_MODE_SIZE (GET_MODE (reg)) > GET_MODE_SIZE (mode) - && ((var_size = int_size_in_bytes (TREE_TYPE (decl))) > 0 - && var_size < GET_MODE_SIZE (GET_MODE (reg)))) - { - int offset_le; - - /* Convert machine endian to little endian WRT size of mode of REG. */ - if (WORDS_BIG_ENDIAN) - offset_le = ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset) - / UNITS_PER_WORD) * UNITS_PER_WORD; - else - offset_le = (offset / UNITS_PER_WORD) * UNITS_PER_WORD; - - if (BYTES_BIG_ENDIAN) - offset_le += ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset) - % UNITS_PER_WORD); - else - offset_le += offset % UNITS_PER_WORD; - - if (offset_le >= var_size) - { - /* MODE is wider than the variable so the new reg will cover - the whole variable so the resulting OFFSET should be 0. */ - offset = 0; - } - else - { - /* Convert little endian to machine endian WRT size of variable. */ - if (WORDS_BIG_ENDIAN) - offset = ((var_size - 1 - offset_le) - / UNITS_PER_WORD) * UNITS_PER_WORD; - else - offset = (offset_le / UNITS_PER_WORD) * UNITS_PER_WORD; - - if (BYTES_BIG_ENDIAN) - offset += ((var_size - 1 - offset_le) - % UNITS_PER_WORD); - else - offset += offset_le % UNITS_PER_WORD; - } - } - REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg), REG_OFFSET (reg) + offset); return new; @@ -924,7 +889,7 @@ set_reg_attrs_from_mem (rtx reg, rtx mem) void set_reg_attrs_for_parm (rtx parm_rtx, rtx mem) { - if (REG_P (parm_rtx)) + if (GET_CODE (parm_rtx) == REG) set_reg_attrs_from_mem (parm_rtx, mem); else if (GET_CODE (parm_rtx) == PARALLEL) { @@ -934,7 +899,7 @@ set_reg_attrs_for_parm (rtx parm_rtx, rtx mem) for (; i < XVECLEN (parm_rtx, 0); i++) { rtx x = XVECEXP (parm_rtx, 0, i); - if (REG_P (XEXP (x, 0))) + if (GET_CODE (XEXP (x, 0)) == REG) REG_ATTRS (XEXP (x, 0)) = get_reg_attrs (MEM_EXPR (mem), INTVAL (XEXP (x, 1))); @@ -946,12 +911,12 @@ set_reg_attrs_for_parm (rtx parm_rtx, rtx mem) void set_decl_rtl (tree t, rtx x) { - DECL_WRTL_CHECK (t)->decl_with_rtl.rtl = x; + DECL_CHECK (t)->decl.rtl = x; if (!x) return; /* For register, we maintain the reverse information too. */ - if (REG_P (x)) + if (GET_CODE (x) == REG) REG_ATTRS (x) = get_reg_attrs (t, 0); else if (GET_CODE (x) == SUBREG) REG_ATTRS (SUBREG_REG (x)) @@ -976,48 +941,6 @@ set_decl_rtl (tree t, rtx x) } } -/* Assign the RTX X to parameter declaration T. */ -void -set_decl_incoming_rtl (tree t, rtx x) -{ - DECL_INCOMING_RTL (t) = x; - - if (!x) - return; - /* For register, we maintain the reverse information too. */ - if (REG_P (x)) - REG_ATTRS (x) = get_reg_attrs (t, 0); - else if (GET_CODE (x) == SUBREG) - REG_ATTRS (SUBREG_REG (x)) - = get_reg_attrs (t, -SUBREG_BYTE (x)); - if (GET_CODE (x) == CONCAT) - { - if (REG_P (XEXP (x, 0))) - REG_ATTRS (XEXP (x, 0)) = get_reg_attrs (t, 0); - if (REG_P (XEXP (x, 1))) - REG_ATTRS (XEXP (x, 1)) - = get_reg_attrs (t, GET_MODE_UNIT_SIZE (GET_MODE (XEXP (x, 0)))); - } - if (GET_CODE (x) == PARALLEL) - { - int i, start; - - /* Check for a NULL entry, used to indicate that the parameter goes - both on the stack and in registers. */ - if (XEXP (XVECEXP (x, 0, 0), 0)) - start = 0; - else - start = 1; - - for (i = start; i < XVECLEN (x, 0); i++) - { - rtx y = XVECEXP (x, 0, i); - if (REG_P (XEXP (y, 0))) - REG_ATTRS (XEXP (y, 0)) = get_reg_attrs (t, INTVAL (XEXP (y, 1))); - } - } -} - /* Identify REG (which may be a CONCAT) as a user register. */ void @@ -1028,11 +951,10 @@ mark_user_reg (rtx reg) REG_USERVAR_P (XEXP (reg, 0)) = 1; REG_USERVAR_P (XEXP (reg, 1)) = 1; } + else if (GET_CODE (reg) == REG) + REG_USERVAR_P (reg) = 1; else - { - gcc_assert (REG_P (reg)); - REG_USERVAR_P (reg) = 1; - } + abort (); } /* Identify REG as a probable pointer register and show its alignment @@ -1066,6 +988,8 @@ max_reg_num (void) int max_label_num (void) { + if (last_label_num && label_num == base_label_num) + return last_label_num; return label_num; } @@ -1076,18 +1000,41 @@ get_first_label_num (void) { return first_label_num; } + +/* Return the final regno of X, which is a SUBREG of a hard + register. */ +int +subreg_hard_regno (rtx x, int check_mode) +{ + enum machine_mode mode = GET_MODE (x); + unsigned int byte_offset, base_regno, final_regno; + rtx reg = SUBREG_REG (x); + + /* This is where we attempt to catch illegal subregs + created by the compiler. */ + if (GET_CODE (x) != SUBREG + || GET_CODE (reg) != REG) + abort (); + base_regno = REGNO (reg); + if (base_regno >= FIRST_PSEUDO_REGISTER) + abort (); + if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg))) + abort (); +#ifdef ENABLE_CHECKING + if (!subreg_offset_representable_p (REGNO (reg), GET_MODE (reg), + SUBREG_BYTE (x), mode)) + abort (); +#endif + /* Catch non-congruent offsets too. */ + byte_offset = SUBREG_BYTE (x); + if ((byte_offset % GET_MODE_SIZE (mode)) != 0) + abort (); -/* If the rtx for label was created during the expansion of a nested - function, then first_label_num won't include this label number. - Fix this now so that array indicies work later. */ + final_regno = subreg_regno (x); -void -maybe_set_first_label_num (rtx x) -{ - if (CODE_LABEL_NUMBER (x) < first_label_num) - first_label_num = CODE_LABEL_NUMBER (x); + return final_regno; } - + /* Return a value representing some low-order bits of X, where the number of low-order bits is given by MODE. Note that no conversion is done between floating-point and fixed-point values, rather, the bit @@ -1110,15 +1057,15 @@ gen_lowpart_common (enum machine_mode mode, rtx x) /* Unfortunately, this routine doesn't take a parameter for the mode of X, so we have to make one up. Yuk. */ innermode = GET_MODE (x); - if (GET_CODE (x) == CONST_INT - && msize * BITS_PER_UNIT <= HOST_BITS_PER_WIDE_INT) + if (GET_CODE (x) == CONST_INT && msize <= HOST_BITS_PER_WIDE_INT) innermode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0); else if (innermode == VOIDmode) innermode = mode_for_size (HOST_BITS_PER_WIDE_INT * 2, MODE_INT, 0); xsize = GET_MODE_SIZE (innermode); - gcc_assert (innermode != VOIDmode && innermode != BLKmode); + if (innermode == VOIDmode || innermode == BLKmode) + abort (); if (innermode == mode) return x; @@ -1129,7 +1076,7 @@ gen_lowpart_common (enum machine_mode mode, rtx x) return 0; /* Don't allow generating paradoxical FLOAT_MODE subregs. */ - if (SCALAR_FLOAT_MODE_P (mode) && msize > xsize) + if (GET_MODE_CLASS (mode) == MODE_FLOAT && msize > xsize) return 0; offset = subreg_lowpart_offset (mode, innermode); @@ -1153,7 +1100,7 @@ gen_lowpart_common (enum machine_mode mode, rtx x) else if (msize < xsize) return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0)); } - else if (GET_CODE (x) == SUBREG || REG_P (x) + else if (GET_CODE (x) == SUBREG || GET_CODE (x) == REG || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR || GET_CODE (x) == CONST_DOUBLE || GET_CODE (x) == CONST_INT) return simplify_gen_subreg (mode, x, innermode, offset); @@ -1162,6 +1109,152 @@ gen_lowpart_common (enum machine_mode mode, rtx x) return 0; } +/* Return the constant real or imaginary part (which has mode MODE) + of a complex value X. The IMAGPART_P argument determines whether + the real or complex component should be returned. This function + returns NULL_RTX if the component isn't a constant. */ + +static rtx +gen_complex_constant_part (enum machine_mode mode, rtx x, int imagpart_p) +{ + tree decl, part; + + if (GET_CODE (x) == MEM + && GET_CODE (XEXP (x, 0)) == SYMBOL_REF) + { + decl = SYMBOL_REF_DECL (XEXP (x, 0)); + if (decl != NULL_TREE && TREE_CODE (decl) == COMPLEX_CST) + { + part = imagpart_p ? TREE_IMAGPART (decl) : TREE_REALPART (decl); + if (TREE_CODE (part) == REAL_CST + || TREE_CODE (part) == INTEGER_CST) + return expand_expr (part, NULL_RTX, mode, 0); + } + } + return NULL_RTX; +} + +/* Return the real part (which has mode MODE) of a complex value X. + This always comes at the low address in memory. */ + +rtx +gen_realpart (enum machine_mode mode, rtx x) +{ + rtx part; + + /* Handle complex constants. */ + part = gen_complex_constant_part (mode, x, 0); + if (part != NULL_RTX) + return part; + + if (WORDS_BIG_ENDIAN + && GET_MODE_BITSIZE (mode) < BITS_PER_WORD + && REG_P (x) + && REGNO (x) < FIRST_PSEUDO_REGISTER) + internal_error + ("can't access real part of complex value in hard register"); + else if (WORDS_BIG_ENDIAN) + return gen_highpart (mode, x); + else + return gen_lowpart (mode, x); +} + +/* Return the imaginary part (which has mode MODE) of a complex value X. + This always comes at the high address in memory. */ + +rtx +gen_imagpart (enum machine_mode mode, rtx x) +{ + rtx part; + + /* Handle complex constants. */ + part = gen_complex_constant_part (mode, x, 1); + if (part != NULL_RTX) + return part; + + if (WORDS_BIG_ENDIAN) + return gen_lowpart (mode, x); + else if (! WORDS_BIG_ENDIAN + && GET_MODE_BITSIZE (mode) < BITS_PER_WORD + && REG_P (x) + && REGNO (x) < FIRST_PSEUDO_REGISTER) + internal_error + ("can't access imaginary part of complex value in hard register"); + else + return gen_highpart (mode, x); +} + +/* Return 1 iff X, assumed to be a SUBREG, + refers to the real part of the complex value in its containing reg. + Complex values are always stored with the real part in the first word, + regardless of WORDS_BIG_ENDIAN. */ + +int +subreg_realpart_p (rtx x) +{ + if (GET_CODE (x) != SUBREG) + abort (); + + return ((unsigned int) SUBREG_BYTE (x) + < (unsigned int) GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x)))); +} + +/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a value, + return an rtx (MEM, SUBREG, or CONST_INT) that refers to the + least-significant part of X. + MODE specifies how big a part of X to return; + it usually should not be larger than a word. + If X is a MEM whose address is a QUEUED, the value may be so also. */ + +rtx +gen_lowpart (enum machine_mode mode, rtx x) +{ + rtx result = gen_lowpart_common (mode, x); + + if (result) + return result; + else if (GET_CODE (x) == REG) + { + /* Must be a hard reg that's not valid in MODE. */ + result = gen_lowpart_common (mode, copy_to_reg (x)); + if (result == 0) + abort (); + return result; + } + else if (GET_CODE (x) == MEM) + { + /* The only additional case we can do is MEM. */ + int offset = 0; + + /* The following exposes the use of "x" to CSE. */ + if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD + && SCALAR_INT_MODE_P (GET_MODE (x)) + && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), + GET_MODE_BITSIZE (GET_MODE (x))) + && ! no_new_pseudos) + return gen_lowpart (mode, force_reg (GET_MODE (x), x)); + + if (WORDS_BIG_ENDIAN) + offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) + - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); + + if (BYTES_BIG_ENDIAN) + /* Adjust the address so that the address-after-the-data + is unchanged. */ + offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) + - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); + + return adjust_address (x, mode, offset); + } + else if (GET_CODE (x) == ADDRESSOF) + return gen_lowpart (mode, force_reg (GET_MODE (x), x)); + else + abort (); +} + +/* Like `gen_lowpart', but refer to the most significant part. + This is used to access the imaginary part of a complex number. */ + rtx gen_highpart (enum machine_mode mode, rtx x) { @@ -1170,22 +1263,21 @@ gen_highpart (enum machine_mode mode, rtx x) /* This case loses if X is a subreg. To catch bugs early, complain if an invalid MODE is used even in other cases. */ - gcc_assert (msize <= UNITS_PER_WORD - || msize == (unsigned int) GET_MODE_UNIT_SIZE (GET_MODE (x))); + if (msize > UNITS_PER_WORD + && msize != (unsigned int) GET_MODE_UNIT_SIZE (GET_MODE (x))) + abort (); result = simplify_gen_subreg (mode, x, GET_MODE (x), subreg_highpart_offset (mode, GET_MODE (x))); - gcc_assert (result); - + /* simplify_gen_subreg is not guaranteed to return a valid operand for the target if we have a MEM. gen_highpart must return a valid operand, emitting code if necessary to do so. */ - if (MEM_P (result)) - { - result = validize_mem (result); - gcc_assert (result); - } - + if (result != NULL_RTX && GET_CODE (result) == MEM) + result = validize_mem (result); + + if (!result) + abort (); return result; } @@ -1196,7 +1288,8 @@ gen_highpart_mode (enum machine_mode outermode, enum machine_mode innermode, rtx { if (GET_MODE (exp) != VOIDmode) { - gcc_assert (GET_MODE (exp) == innermode); + if (GET_MODE (exp) != innermode) + abort (); return gen_highpart (outermode, exp); } return simplify_gen_subreg (outermode, exp, innermode, @@ -1231,7 +1324,8 @@ subreg_highpart_offset (enum machine_mode outermode, enum machine_mode innermode unsigned int offset = 0; int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode)); - gcc_assert (GET_MODE_SIZE (innermode) >= GET_MODE_SIZE (outermode)); + if (GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode)) + abort (); if (difference > 0) { @@ -1291,7 +1385,8 @@ operand_subword (rtx op, unsigned int offset, int validate_address, enum machine if (mode == VOIDmode) mode = GET_MODE (op); - gcc_assert (mode != VOIDmode); + if (mode == VOIDmode) + abort (); /* If OP is narrower than a word, fail. */ if (mode != BLKmode @@ -1304,7 +1399,7 @@ operand_subword (rtx op, unsigned int offset, int validate_address, enum machine return const0_rtx; /* Form a new MEM at the requested address. */ - if (MEM_P (op)) + if (GET_CODE (op) == MEM) { rtx new = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD); @@ -1324,10 +1419,9 @@ operand_subword (rtx op, unsigned int offset, int validate_address, enum machine return simplify_gen_subreg (word_mode, op, mode, (offset * UNITS_PER_WORD)); } -/* Similar to `operand_subword', but never return 0. If we can't - extract the required subword, put OP into a register and try again. - The second attempt must succeed. We always validate the address in - this case. +/* Similar to `operand_subword', but never return 0. If we can't extract + the required subword, put OP into a register and try again. If that fails, + abort. We always validate the address in this case. MODE is the mode of OP, in case it is CONST_INT. */ @@ -1343,18 +1437,51 @@ operand_subword_force (rtx op, unsigned int offset, enum machine_mode mode) { /* If this is a register which can not be accessed by words, copy it to a pseudo register. */ - if (REG_P (op)) + if (GET_CODE (op) == REG) op = copy_to_reg (op); else op = force_reg (mode, op); } result = operand_subword (op, offset, 1, mode); - gcc_assert (result); + if (result == 0) + abort (); return result; } +/* Given a compare instruction, swap the operands. + A test instruction is changed into a compare of 0 against the operand. */ + +void +reverse_comparison (rtx insn) +{ + rtx body = PATTERN (insn); + rtx comp; + + if (GET_CODE (body) == SET) + comp = SET_SRC (body); + else + comp = SET_SRC (XVECEXP (body, 0, 0)); + + if (GET_CODE (comp) == COMPARE) + { + rtx op0 = XEXP (comp, 0); + rtx op1 = XEXP (comp, 1); + XEXP (comp, 0) = op1; + XEXP (comp, 1) = op0; + } + else + { + rtx new = gen_rtx_COMPARE (VOIDmode, + CONST0_RTX (GET_MODE (comp)), comp); + if (GET_CODE (body) == SET) + SET_SRC (body) = new; + else + SET_SRC (XVECEXP (body, 0, 0)) = new; + } +} + /* Within a MEM_EXPR, we care about either (1) a component ref of a decl, or (2) a component ref of something variable. Represent the later with a NULL expression. */ @@ -1368,13 +1495,19 @@ component_ref_for_mem_expr (tree ref) inner = component_ref_for_mem_expr (inner); else { + tree placeholder_ptr = 0; + /* Now remove any conversions: they don't change what the underlying - object is. Likewise for SAVE_EXPR. */ + object is. Likewise for SAVE_EXPR. Also handle PLACEHOLDER_EXPR. */ while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR || TREE_CODE (inner) == NON_LVALUE_EXPR || TREE_CODE (inner) == VIEW_CONVERT_EXPR - || TREE_CODE (inner) == SAVE_EXPR) - inner = TREE_OPERAND (inner, 0); + || TREE_CODE (inner) == SAVE_EXPR + || TREE_CODE (inner) == PLACEHOLDER_EXPR) + if (TREE_CODE (inner) == PLACEHOLDER_EXPR) + inner = find_placeholder (inner, &placeholder_ptr); + else + inner = TREE_OPERAND (inner, 0); if (! DECL_P (inner)) inner = NULL_TREE; @@ -1383,8 +1516,8 @@ component_ref_for_mem_expr (tree ref) if (inner == TREE_OPERAND (ref, 0)) return ref; else - return build3 (COMPONENT_REF, TREE_TYPE (ref), inner, - TREE_OPERAND (ref, 1), NULL_TREE); + return build (COMPONENT_REF, TREE_TYPE (ref), inner, + TREE_OPERAND (ref, 1)); } /* Returns 1 if both MEM_EXPR can be considered equal @@ -1409,16 +1542,16 @@ mem_expr_equal_p (tree expr1, tree expr2) && mem_expr_equal_p (TREE_OPERAND (expr1, 1), /* field decl */ TREE_OPERAND (expr2, 1)); - if (INDIRECT_REF_P (expr1)) + if (TREE_CODE (expr1) == INDIRECT_REF) return mem_expr_equal_p (TREE_OPERAND (expr1, 0), TREE_OPERAND (expr2, 0)); - - /* ARRAY_REFs, ARRAY_RANGE_REFs and BIT_FIELD_REFs should already - have been resolved here. */ - gcc_assert (DECL_P (expr1)); /* Decls with different pointers can't be equal. */ - return 0; + if (DECL_P (expr1)) + return 0; + + abort(); /* ARRAY_REFs, ARRAY_RANGE_REFs and BIT_FIELD_REFs should already + have been resolved here. */ } /* Given REF, a MEM, and T, either the type of X or the expression @@ -1452,15 +1585,19 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, wrong answer, as it assumes that DECL_RTL already has the right alias info. Callers should not set DECL_RTL until after the call to set_mem_attributes. */ - gcc_assert (!DECL_P (t) || ref != DECL_RTL_IF_SET (t)); + if (DECL_P (t) && ref == DECL_RTL_IF_SET (t)) + abort (); /* Get the alias set from the expression or type (perhaps using a front-end routine) and use it. */ alias = get_alias_set (t); - MEM_VOLATILE_P (ref) |= TYPE_VOLATILE (type); + MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type); MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type); - MEM_POINTER (ref) = POINTER_TYPE_P (type); + RTX_UNCHANGING_P (ref) + |= ((lang_hooks.honor_readonly + && (TYPE_READONLY (type) || TREE_READONLY (t))) + || (! TYPE_P (t) && TREE_CONSTANT (t))); /* If we are making an object of this type, or if this is a DECL, we know that it is a scalar if the type is not an aggregate. */ @@ -1469,19 +1606,8 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, /* We can set the alignment from the type if we are making an object, this is an INDIRECT_REF, or if TYPE_ALIGN_OK. */ - if (objectp || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ALIGN_INDIRECT_REF - || TYPE_ALIGN_OK (type)) + if (objectp || TREE_CODE (t) == INDIRECT_REF || TYPE_ALIGN_OK (type)) align = MAX (align, TYPE_ALIGN (type)); - else - if (TREE_CODE (t) == MISALIGNED_INDIRECT_REF) - { - if (integer_zerop (TREE_OPERAND (t, 1))) - /* We don't know anything about the alignment. */ - align = BITS_PER_UNIT; - else - align = tree_low_cst (TREE_OPERAND (t, 1), 1); - } /* If the size is known, we can set that. */ if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1)) @@ -1491,8 +1617,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, the expression. */ if (! TYPE_P (t)) { - tree base; - + maybe_set_unchanging (ref, t); if (TREE_THIS_VOLATILE (t)) MEM_VOLATILE_P (ref) = 1; @@ -1504,39 +1629,9 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, || TREE_CODE (t) == SAVE_EXPR) t = TREE_OPERAND (t, 0); - /* We may look through structure-like accesses for the purposes of - examining TREE_THIS_NOTRAP, but not array-like accesses. */ - base = t; - while (TREE_CODE (base) == COMPONENT_REF - || TREE_CODE (base) == REALPART_EXPR - || TREE_CODE (base) == IMAGPART_EXPR - || TREE_CODE (base) == BIT_FIELD_REF) - base = TREE_OPERAND (base, 0); - - if (DECL_P (base)) - { - if (CODE_CONTAINS_STRUCT (TREE_CODE (base), TS_DECL_WITH_VIS)) - MEM_NOTRAP_P (ref) = !DECL_WEAK (base); - else - MEM_NOTRAP_P (ref) = 1; - } - else - MEM_NOTRAP_P (ref) = TREE_THIS_NOTRAP (base); - - base = get_base_address (base); - if (base && DECL_P (base) - && TREE_READONLY (base) - && (TREE_STATIC (base) || DECL_EXTERNAL (base))) - { - tree base_type = TREE_TYPE (base); - gcc_assert (!(base_type && TYPE_NEEDS_CONSTRUCTING (base_type)) - || DECL_ARTIFICIAL (base)); - MEM_READONLY_P (ref) = 1; - } - - /* If this expression uses it's parent's alias set, mark it such - that we won't change it. */ - if (component_uses_parent_alias_set (t)) + /* If this expression can't be addressed (e.g., it contains a reference + to a non-addressable field), show we don't change its alias set. */ + if (! can_address_p (t)) MEM_KEEP_ALIAS_SET_P (ref) = 1; /* If this is a decl, set the attributes of the MEM from it. */ @@ -1552,7 +1647,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, } /* If this is a constant, we know the alignment. */ - else if (CONSTANT_CLASS_P (t)) + else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'c') { align = TYPE_ALIGN (type); #ifdef CONSTANT_ALIGNMENT @@ -1585,23 +1680,34 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, do { tree index = TREE_OPERAND (t2, 1); - tree low_bound = array_ref_low_bound (t2); - tree unit_size = array_ref_element_size (t2); + tree array = TREE_OPERAND (t2, 0); + tree domain = TYPE_DOMAIN (TREE_TYPE (array)); + tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0); + tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array))); /* We assume all arrays have sizes that are a multiple of a byte. First subtract the lower bound, if any, in the type of the - index, then convert to sizetype and multiply by the size of - the array element. */ - if (! integer_zerop (low_bound)) - index = fold_build2 (MINUS_EXPR, TREE_TYPE (index), - index, low_bound); - - off_tree = size_binop (PLUS_EXPR, - size_binop (MULT_EXPR, - fold_convert (sizetype, - index), - unit_size), - off_tree); + index, then convert to sizetype and multiply by the size of the + array element. */ + if (low_bound != 0 && ! integer_zerop (low_bound)) + index = fold (build (MINUS_EXPR, TREE_TYPE (index), + index, low_bound)); + + /* If the index has a self-referential type, pass it to a + WITH_RECORD_EXPR; if the component size is, pass our + component to one. */ + if (CONTAINS_PLACEHOLDER_P (index)) + index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, t2); + if (CONTAINS_PLACEHOLDER_P (unit_size)) + unit_size = build (WITH_RECORD_EXPR, sizetype, + unit_size, array); + + off_tree + = fold (build (PLUS_EXPR, sizetype, + fold (build (MULT_EXPR, sizetype, + index, + unit_size)), + off_tree)); t2 = TREE_OPERAND (t2, 0); } while (TREE_CODE (t2) == ARRAY_REF); @@ -1633,7 +1739,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, the size we got from the type? */ } else if (flag_argument_noalias > 1 - && (INDIRECT_REF_P (t2)) + && TREE_CODE (t2) == INDIRECT_REF && TREE_CODE (TREE_OPERAND (t2, 0)) == PARM_DECL) { expr = t2; @@ -1644,7 +1750,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, /* If this is a Fortran indirect argument reference, record the parameter decl. */ else if (flag_argument_noalias > 1 - && (INDIRECT_REF_P (t)) + && TREE_CODE (t) == INDIRECT_REF && TREE_CODE (TREE_OPERAND (t, 0)) == PARM_DECL) { expr = t; @@ -1662,14 +1768,6 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, size = plus_constant (size, apply_bitpos / BITS_PER_UNIT); } - if (TREE_CODE (t) == ALIGN_INDIRECT_REF) - { - /* Force EXPR and OFFSE to NULL, since we don't know exactly what - we're overlapping. */ - offset = NULL; - expr = NULL; - } - /* Now set the attributes we computed above. */ MEM_ATTRS (ref) = get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref)); @@ -1710,7 +1808,8 @@ set_mem_alias_set (rtx mem, HOST_WIDE_INT set) { #ifdef ENABLE_CHECKING /* If the new and old alias sets don't conflict, something is wrong. */ - gcc_assert (alias_sets_conflict_p (set, MEM_ALIAS_SET (mem))); + if (!alias_sets_conflict_p (set, MEM_ALIAS_SET (mem))) + abort (); #endif MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem), @@ -1769,7 +1868,8 @@ change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) { rtx new; - gcc_assert (MEM_P (memref)); + if (GET_CODE (memref) != MEM) + abort (); if (mode == VOIDmode) mode = GET_MODE (memref); if (addr == 0) @@ -1781,7 +1881,10 @@ change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) if (validate) { if (reload_in_progress || reload_completed) - gcc_assert (memory_address_p (mode, addr)); + { + if (! memory_address_p (mode, addr)) + abort (); + } else addr = memory_address (mode, addr); } @@ -2000,7 +2103,6 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset) if (TREE_CODE (expr) == COMPONENT_REF) { tree field = TREE_OPERAND (expr, 1); - tree offset = component_ref_field_offset (expr); if (! DECL_SIZE_UNIT (field)) { @@ -2015,18 +2117,17 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset) && INTVAL (memoffset) >= 0) break; - if (! host_integerp (offset, 1)) + if (! host_integerp (DECL_FIELD_OFFSET (field), 1)) { expr = NULL_TREE; break; } expr = TREE_OPERAND (expr, 0); - memoffset - = (GEN_INT (INTVAL (memoffset) - + tree_low_cst (offset, 1) - + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1) - / BITS_PER_UNIT))); + memoffset = (GEN_INT (INTVAL (memoffset) + + tree_low_cst (DECL_FIELD_OFFSET (field), 1) + + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1) + / BITS_PER_UNIT))); } /* Similarly for the decl. */ else if (DECL_P (expr) @@ -2085,12 +2186,31 @@ set_new_first_and_last_insn (rtx first, rtx last) cur_insn_uid++; } + +/* Set the last label number found in the current function. + This is used when belatedly compiling an inline function. */ + +void +set_new_last_label_num (int last) +{ + base_label_num = label_num; + last_label_num = last; +} + +/* Restore all variables describing the current status from the structure *P. + This is used after a nested function. */ + +void +restore_emit_status (struct function *p ATTRIBUTE_UNUSED) +{ + last_label_num = 0; +} /* Go through all the RTL insn bodies and copy any invalid shared structure. This routine should only be called once. */ -static void -unshare_all_rtl_1 (tree fndecl, rtx insn) +void +unshare_all_rtl (tree fndecl, rtx insn) { tree decl; @@ -2141,34 +2261,9 @@ unshare_all_rtl_again (rtx insn) reset_used_flags (stack_slot_list); - unshare_all_rtl_1 (cfun->decl, insn); -} - -unsigned int -unshare_all_rtl (void) -{ - unshare_all_rtl_1 (current_function_decl, get_insns ()); - return 0; + unshare_all_rtl (cfun->decl, insn); } -struct tree_opt_pass pass_unshare_all_rtl = -{ - "unshare", /* name */ - NULL, /* gate */ - unshare_all_rtl, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - 0, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ -}; - - /* Check that ORIG is not marked when it should not be and mark ORIG as in use, Recursively does the same for subexpressions. */ @@ -2190,6 +2285,7 @@ verify_rtx_sharing (rtx orig, rtx insn) switch (code) { case REG: + case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -2199,12 +2295,8 @@ verify_rtx_sharing (rtx orig, rtx insn) case PC: case CC0: case SCRATCH: - return; /* SCRATCH must be shared because they represent distinct values. */ - case CLOBBER: - if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER) - return; - break; + return; case CONST: /* CONST can be shared if it contains a SYMBOL_REF. If it contains @@ -2229,18 +2321,15 @@ verify_rtx_sharing (rtx orig, rtx insn) /* This rtx may not be shared. If it has already been seen, replace it with a copy of itself. */ -#ifdef ENABLE_CHECKING + if (RTX_FLAG (x, used)) { - error ("invalid rtl sharing found in the insn"); + error ("Invalid rtl sharing found in the insn"); debug_rtx (insn); - error ("shared rtx"); + error ("Shared rtx"); debug_rtx (x); - internal_error ("internal consistency failure"); + abort (); } -#endif - gcc_assert (!RTX_FLAG (x, used)); - RTX_FLAG (x, used) = 1; /* Now scan the subexpressions recursively. */ @@ -2263,11 +2352,9 @@ verify_rtx_sharing (rtx orig, rtx insn) for (j = 0; j < len; j++) { - /* We allow sharing of ASM_OPERANDS inside single - instruction. */ + /* We allow sharing of ASM_OPERANDS inside single instruction. */ if (j && GET_CODE (XVECEXP (x, i, j)) == SET - && (GET_CODE (SET_SRC (XVECEXP (x, i, j))) - == ASM_OPERANDS)) + && GET_CODE (SET_SRC (XVECEXP (x, i, j))) == ASM_OPERANDS) verify_rtx_sharing (SET_DEST (XVECEXP (x, i, j)), insn); else verify_rtx_sharing (XVECEXP (x, i, j), insn); @@ -2353,6 +2440,106 @@ reset_used_decls (tree blk) reset_used_decls (t); } +/* Similar to `copy_rtx' except that if MAY_SHARE is present, it is + placed in the result directly, rather than being copied. MAY_SHARE is + either a MEM of an EXPR_LIST of MEMs. */ + +rtx +copy_most_rtx (rtx orig, rtx may_share) +{ + rtx copy; + int i, j; + RTX_CODE code; + const char *format_ptr; + + if (orig == may_share + || (GET_CODE (may_share) == EXPR_LIST + && in_expr_list_p (may_share, orig))) + return orig; + + code = GET_CODE (orig); + + switch (code) + { + case REG: + case QUEUED: + case CONST_INT: + case CONST_DOUBLE: + case CONST_VECTOR: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + return orig; + default: + break; + } + + copy = rtx_alloc (code); + PUT_MODE (copy, GET_MODE (orig)); + RTX_FLAG (copy, in_struct) = RTX_FLAG (orig, in_struct); + RTX_FLAG (copy, volatil) = RTX_FLAG (orig, volatil); + RTX_FLAG (copy, unchanging) = RTX_FLAG (orig, unchanging); + RTX_FLAG (copy, integrated) = RTX_FLAG (orig, integrated); + RTX_FLAG (copy, frame_related) = RTX_FLAG (orig, frame_related); + + format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); + + for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) + { + switch (*format_ptr++) + { + case 'e': + XEXP (copy, i) = XEXP (orig, i); + if (XEXP (orig, i) != NULL && XEXP (orig, i) != may_share) + XEXP (copy, i) = copy_most_rtx (XEXP (orig, i), may_share); + break; + + case 'u': + XEXP (copy, i) = XEXP (orig, i); + break; + + case 'E': + case 'V': + XVEC (copy, i) = XVEC (orig, i); + if (XVEC (orig, i) != NULL) + { + XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); + for (j = 0; j < XVECLEN (copy, i); j++) + XVECEXP (copy, i, j) + = copy_most_rtx (XVECEXP (orig, i, j), may_share); + } + break; + + case 'w': + XWINT (copy, i) = XWINT (orig, i); + break; + + case 'n': + case 'i': + XINT (copy, i) = XINT (orig, i); + break; + + case 't': + XTREE (copy, i) = XTREE (orig, i); + break; + + case 's': + case 'S': + XSTR (copy, i) = XSTR (orig, i); + break; + + case '0': + X0ANY (copy, i) = X0ANY (orig, i); + break; + + default: + abort (); + } + } + return copy; +} + /* Mark ORIG as in use, and return a copy of it if it was already in use. Recursively does the same for subexpressions. Uses copy_rtx_if_shared_1 to reduce stack space. */ @@ -2392,6 +2579,7 @@ repeat: switch (code) { case REG: + case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -2403,10 +2591,6 @@ repeat: case SCRATCH: /* SCRATCH must be shared because they represent distinct values. */ return; - case CLOBBER: - if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER) - return; - break; case CONST: /* CONST can be shared if it contains a SYMBOL_REF. If it contains @@ -2434,7 +2618,11 @@ repeat: if (RTX_FLAG (x, used)) { - x = shallow_copy_rtx (x); + rtx copy; + + copy = rtx_alloc (code); + memcpy (copy, x, RTX_SIZE (code)); + x = copy; copied = 1; } RTX_FLAG (x, used) = 1; @@ -2513,6 +2701,7 @@ repeat: switch (code) { case REG: + case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -2582,6 +2771,7 @@ set_used_flags (rtx x) switch (code) { case REG: + case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -2645,11 +2835,11 @@ make_safe_from (rtx x, rtx other) goto done; } done: - if ((MEM_P (other) + if ((GET_CODE (other) == MEM && ! CONSTANT_P (x) - && !REG_P (x) + && GET_CODE (x) != REG && GET_CODE (x) != SUBREG) - || (REG_P (other) + || (GET_CODE (other) == REG && (REGNO (other) < FIRST_PSEUDO_REGISTER || reg_mentioned_p (other, x)))) { @@ -2675,7 +2865,8 @@ get_insns (void) void set_first_insn (rtx insn) { - gcc_assert (!PREV_INSN (insn)); + if (PREV_INSN (insn) != 0) + abort (); first_insn = insn; } @@ -2692,7 +2883,8 @@ get_last_insn (void) void set_last_insn (rtx insn) { - gcc_assert (!NEXT_INSN (insn)); + if (NEXT_INSN (insn) != 0) + abort (); last_insn = insn; } @@ -2727,7 +2919,7 @@ get_first_nonnote_insn (void) continue; else { - if (NONJUMP_INSN_P (insn) + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) insn = XVECEXP (PATTERN (insn), 0, 0); } @@ -2753,7 +2945,7 @@ get_last_nonnote_insn (void) continue; else { - if (NONJUMP_INSN_P (insn) + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) insn = XVECEXP (PATTERN (insn), 0, XVECLEN (PATTERN (insn), 0) - 1); @@ -2774,7 +2966,7 @@ get_max_uid (void) /* Renumber instructions so that no instruction UIDs are wasted. */ void -renumber_insns (void) +renumber_insns (FILE *stream) { rtx insn; @@ -2791,8 +2983,8 @@ renumber_insns (void) for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { - if (dump_file) - fprintf (dump_file, "Renumbering insn %d to %d\n", + if (stream) + fprintf (stream, "Renumbering insn %d to %d\n", INSN_UID (insn), cur_insn_uid); INSN_UID (insn) = cur_insn_uid++; } @@ -2807,7 +2999,7 @@ next_insn (rtx insn) if (insn) { insn = NEXT_INSN (insn); - if (insn && NONJUMP_INSN_P (insn) + if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) insn = XVECEXP (PATTERN (insn), 0, 0); } @@ -2824,7 +3016,7 @@ previous_insn (rtx insn) if (insn) { insn = PREV_INSN (insn); - if (insn && NONJUMP_INSN_P (insn) + if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) insn = XVECEXP (PATTERN (insn), 0, XVECLEN (PATTERN (insn), 0) - 1); } @@ -2841,7 +3033,7 @@ next_nonnote_insn (rtx insn) while (insn) { insn = NEXT_INSN (insn); - if (insn == 0 || !NOTE_P (insn)) + if (insn == 0 || GET_CODE (insn) != NOTE) break; } @@ -2857,7 +3049,7 @@ prev_nonnote_insn (rtx insn) while (insn) { insn = PREV_INSN (insn); - if (insn == 0 || !NOTE_P (insn)) + if (insn == 0 || GET_CODE (insn) != NOTE) break; } @@ -2874,7 +3066,8 @@ next_real_insn (rtx insn) while (insn) { insn = NEXT_INSN (insn); - if (insn == 0 || INSN_P (insn)) + if (insn == 0 || GET_CODE (insn) == INSN + || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) break; } @@ -2891,7 +3084,8 @@ prev_real_insn (rtx insn) while (insn) { insn = PREV_INSN (insn); - if (insn == 0 || INSN_P (insn)) + if (insn == 0 || GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN + || GET_CODE (insn) == JUMP_INSN) break; } @@ -2907,7 +3101,7 @@ last_call_insn (void) rtx insn; for (insn = get_last_insn (); - insn && !CALL_P (insn); + insn && GET_CODE (insn) != CALL_INSN; insn = PREV_INSN (insn)) ; @@ -2921,8 +3115,8 @@ last_call_insn (void) int active_insn_p (rtx insn) { - return (CALL_P (insn) || JUMP_P (insn) - || (NONJUMP_INSN_P (insn) + return (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN + || (GET_CODE (insn) == INSN && (! reload_completed || (GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)))); @@ -2966,7 +3160,7 @@ next_label (rtx insn) while (insn) { insn = NEXT_INSN (insn); - if (insn == 0 || LABEL_P (insn)) + if (insn == 0 || GET_CODE (insn) == CODE_LABEL) break; } @@ -2981,27 +3175,12 @@ prev_label (rtx insn) while (insn) { insn = PREV_INSN (insn); - if (insn == 0 || LABEL_P (insn)) + if (insn == 0 || GET_CODE (insn) == CODE_LABEL) break; } return insn; } - -/* Return the last label to mark the same position as LABEL. Return null - if LABEL itself is null. */ - -rtx -skip_consecutive_labels (rtx label) -{ - rtx insn; - - for (insn = label; insn != 0 && !INSN_P (insn); insn = NEXT_INSN (insn)) - if (LABEL_P (insn)) - label = insn; - - return label; -} #ifdef HAVE_cc0 /* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER @@ -3012,7 +3191,7 @@ link_cc0_insns (rtx insn) { rtx user = next_nonnote_insn (insn); - if (NONJUMP_INSN_P (user) && GET_CODE (PATTERN (user)) == SEQUENCE) + if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE) user = XVECEXP (PATTERN (user), 0, 0); REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn, @@ -3038,7 +3217,7 @@ next_cc0_user (rtx insn) return XEXP (note, 0); insn = next_nonnote_insn (insn); - if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) + if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) insn = XVECEXP (PATTERN (insn), 0, 0); if (insn && INSN_P (insn) && reg_mentioned_p (cc0_rtx, PATTERN (insn))) @@ -3059,7 +3238,8 @@ prev_cc0_setter (rtx insn) return XEXP (note, 0); insn = prev_nonnote_insn (insn); - gcc_assert (sets_cc0_p (PATTERN (insn))); + if (! sets_cc0_p (PATTERN (insn))) + abort (); return insn; } @@ -3122,7 +3302,7 @@ try_split (rtx pat, rtx trial, int last) /* If we are splitting a JUMP_INSN, it might be followed by a BARRIER. We may need to handle this specially. */ - if (after && BARRIER_P (after)) + if (after && GET_CODE (after) == BARRIER) { has_barrier = 1; after = NEXT_INSN (after); @@ -3147,7 +3327,7 @@ try_split (rtx pat, rtx trial, int last) /* Mark labels. */ for (insn = insn_last; insn ; insn = PREV_INSN (insn)) { - if (JUMP_P (insn)) + if (GET_CODE (insn) == JUMP_INSN) { mark_jump_label (PATTERN (insn), insn, 0); njumps++; @@ -3159,7 +3339,8 @@ try_split (rtx pat, rtx trial, int last) one jump is created, otherwise the machine description is responsible for this step using split_branch_probability variable. */ - gcc_assert (njumps == 1); + if (njumps != 1) + abort (); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (probability), @@ -3170,10 +3351,10 @@ try_split (rtx pat, rtx trial, int last) /* If we are splitting a CALL_INSN, look for the CALL_INSN in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it. */ - if (CALL_P (trial)) + if (GET_CODE (trial) == CALL_INSN) { for (insn = insn_last; insn ; insn = PREV_INSN (insn)) - if (CALL_P (insn)) + if (GET_CODE (insn) == CALL_INSN) { rtx *p = &CALL_INSN_FUNCTION_USAGE (insn); while (*p) @@ -3192,8 +3373,8 @@ try_split (rtx pat, rtx trial, int last) insn = insn_last; while (insn != NULL_RTX) { - if (CALL_P (insn) - || (flag_non_call_exceptions && INSN_P (insn) + if (GET_CODE (insn) == CALL_INSN + || (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))) REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, @@ -3205,10 +3386,11 @@ try_split (rtx pat, rtx trial, int last) case REG_NORETURN: case REG_SETJMP: + case REG_ALWAYS_RETURN: insn = insn_last; while (insn != NULL_RTX) { - if (CALL_P (insn)) + if (GET_CODE (insn) == CALL_INSN) REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note), XEXP (note, 0), @@ -3221,7 +3403,7 @@ try_split (rtx pat, rtx trial, int last) insn = insn_last; while (insn != NULL_RTX) { - if (JUMP_P (insn)) + if (GET_CODE (insn) == JUMP_INSN) REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note), XEXP (note, 0), @@ -3237,12 +3419,12 @@ try_split (rtx pat, rtx trial, int last) /* If there are LABELS inside the split insns increment the usage count so we don't delete the label. */ - if (NONJUMP_INSN_P (trial)) + if (GET_CODE (trial) == INSN) { insn = insn_last; while (insn != NULL_RTX) { - if (NONJUMP_INSN_P (insn)) + if (GET_CODE (insn) == INSN) mark_label_nuses (PATTERN (insn)); insn = PREV_INSN (insn); @@ -3296,7 +3478,7 @@ make_insn_raw (rtx pattern) || (GET_CODE (insn) == SET && SET_DEST (insn) == pc_rtx))) { - warning (0, "ICE: emit_insn used where emit_jump_insn needed:\n"); + warning ("ICE: emit_insn used where emit_jump_insn needed:\n"); debug_rtx (insn); } #endif @@ -3306,7 +3488,7 @@ make_insn_raw (rtx pattern) /* Like `make_insn_raw' but make a JUMP_INSN instead of an insn. */ -rtx +static rtx make_jump_insn_raw (rtx pattern) { rtx insn; @@ -3375,7 +3557,8 @@ add_insn_after (rtx insn, rtx after) rtx next = NEXT_INSN (after); basic_block bb; - gcc_assert (!optimize || !INSN_DELETED_P (after)); + if (optimize && INSN_DELETED_P (after)) + abort (); NEXT_INSN (insn) = next; PREV_INSN (insn) = after; @@ -3383,7 +3566,7 @@ add_insn_after (rtx insn, rtx after) if (next) { PREV_INSN (next) = insn; - if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE) + if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE) PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = insn; } else if (last_insn == after) @@ -3399,11 +3582,12 @@ add_insn_after (rtx insn, rtx after) break; } - gcc_assert (stack); + if (stack == 0) + abort (); } - if (!BARRIER_P (after) - && !BARRIER_P (insn) + if (GET_CODE (after) != BARRIER + && GET_CODE (insn) != BARRIER && (bb = BLOCK_FOR_INSN (after))) { set_block_for_insn (insn, bb); @@ -3413,14 +3597,14 @@ add_insn_after (rtx insn, rtx after) either NOTE or LABEL. */ if (BB_END (bb) == after /* Avoid clobbering of structure when creating new BB. */ - && !BARRIER_P (insn) - && (!NOTE_P (insn) + && GET_CODE (insn) != BARRIER + && (GET_CODE (insn) != NOTE || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)) BB_END (bb) = insn; } NEXT_INSN (after) = insn; - if (NONJUMP_INSN_P (after) && GET_CODE (PATTERN (after)) == SEQUENCE) + if (GET_CODE (after) == INSN && GET_CODE (PATTERN (after)) == SEQUENCE) { rtx sequence = PATTERN (after); NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn; @@ -3438,7 +3622,8 @@ add_insn_before (rtx insn, rtx before) rtx prev = PREV_INSN (before); basic_block bb; - gcc_assert (!optimize || !INSN_DELETED_P (before)); + if (optimize && INSN_DELETED_P (before)) + abort (); PREV_INSN (insn) = prev; NEXT_INSN (insn) = before; @@ -3446,7 +3631,7 @@ add_insn_before (rtx insn, rtx before) if (prev) { NEXT_INSN (prev) = insn; - if (NONJUMP_INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE) + if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE) { rtx sequence = PATTERN (prev); NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn; @@ -3465,27 +3650,29 @@ add_insn_before (rtx insn, rtx before) break; } - gcc_assert (stack); + if (stack == 0) + abort (); } - if (!BARRIER_P (before) - && !BARRIER_P (insn) + if (GET_CODE (before) != BARRIER + && GET_CODE (insn) != BARRIER && (bb = BLOCK_FOR_INSN (before))) { set_block_for_insn (insn, bb); if (INSN_P (insn)) bb->flags |= BB_DIRTY; - /* Should not happen as first in the BB is always either NOTE or - LABEL. */ - gcc_assert (BB_HEAD (bb) != insn - /* Avoid clobbering of structure when creating new BB. */ - || BARRIER_P (insn) - || (NOTE_P (insn) - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK)); + /* Should not happen as first in the BB is always + either NOTE or LABEl. */ + if (BB_HEAD (bb) == insn + /* Avoid clobbering of structure when creating new BB. */ + && GET_CODE (insn) != BARRIER + && (GET_CODE (insn) != NOTE + || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)) + abort (); } PREV_INSN (before) = insn; - if (NONJUMP_INSN_P (before) && GET_CODE (PATTERN (before)) == SEQUENCE) + if (GET_CODE (before) == INSN && GET_CODE (PATTERN (before)) == SEQUENCE) PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn; } @@ -3501,7 +3688,7 @@ remove_insn (rtx insn) if (prev) { NEXT_INSN (prev) = next; - if (NONJUMP_INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE) + if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE) { rtx sequence = PATTERN (prev); NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = next; @@ -3520,13 +3707,14 @@ remove_insn (rtx insn) break; } - gcc_assert (stack); + if (stack == 0) + abort (); } if (next) { PREV_INSN (next) = prev; - if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE) + if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE) PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = prev; } else if (last_insn == insn) @@ -3542,9 +3730,10 @@ remove_insn (rtx insn) break; } - gcc_assert (stack); + if (stack == 0) + abort (); } - if (!BARRIER_P (insn) + if (GET_CODE (insn) != BARRIER && (bb = BLOCK_FOR_INSN (insn))) { if (INSN_P (insn)) @@ -3553,7 +3742,8 @@ remove_insn (rtx insn) { /* Never ever delete the basic block note without deleting whole basic block. */ - gcc_assert (!NOTE_P (insn)); + if (GET_CODE (insn) == NOTE) + abort (); BB_HEAD (bb) = next; } if (BB_END (bb) == insn) @@ -3566,7 +3756,8 @@ remove_insn (rtx insn) void add_function_usage_to (rtx call_insn, rtx call_fusage) { - gcc_assert (call_insn && CALL_P (call_insn)); + if (! call_insn || GET_CODE (call_insn) != CALL_INSN) + abort (); /* Put the register usage information on the CALL. If there is already some usage information, put ours at the end. */ @@ -3640,13 +3831,13 @@ reorder_insns (rtx from, rtx to, rtx after) reorder_insns_nobb (from, to, after); - if (!BARRIER_P (after) + if (GET_CODE (after) != BARRIER && (bb = BLOCK_FOR_INSN (after))) { rtx x; bb->flags |= BB_DIRTY; - if (!BARRIER_P (from) + if (GET_CODE (from) != BARRIER && (bb2 = BLOCK_FOR_INSN (from))) { if (BB_END (bb2) == to) @@ -3658,8 +3849,7 @@ reorder_insns (rtx from, rtx to, rtx after) BB_END (bb) = to; for (x = from; x != NEXT_INSN (to); x = NEXT_INSN (x)) - if (!BARRIER_P (x)) - set_block_for_insn (x, bb); + set_block_for_insn (x, bb); } } @@ -3672,13 +3862,146 @@ find_line_note (rtx insn) return 0; for (; insn; insn = PREV_INSN (insn)) - if (NOTE_P (insn) + if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) >= 0) break; return insn; } +/* Like reorder_insns, but inserts line notes to preserve the line numbers + of the moved insns when debugging. This may insert a note between AFTER + and FROM, and another one after TO. */ + +void +reorder_insns_with_line_notes (rtx from, rtx to, rtx after) +{ + rtx from_line = find_line_note (from); + rtx after_line = find_line_note (after); + + reorder_insns (from, to, after); + + if (from_line == after_line) + return; + + if (from_line) + emit_note_copy_after (from_line, after); + if (after_line) + emit_note_copy_after (after_line, to); +} + +/* Remove unnecessary notes from the instruction stream. */ + +void +remove_unnecessary_notes (void) +{ + rtx block_stack = NULL_RTX; + rtx eh_stack = NULL_RTX; + rtx insn; + rtx next; + rtx tmp; + + /* We must not remove the first instruction in the function because + the compiler depends on the first instruction being a note. */ + for (insn = NEXT_INSN (get_insns ()); insn; insn = next) + { + /* Remember what's next. */ + next = NEXT_INSN (insn); + + /* We're only interested in notes. */ + if (GET_CODE (insn) != NOTE) + continue; + + switch (NOTE_LINE_NUMBER (insn)) + { + case NOTE_INSN_DELETED: + case NOTE_INSN_LOOP_END_TOP_COND: + remove_insn (insn); + break; + + case NOTE_INSN_EH_REGION_BEG: + eh_stack = alloc_INSN_LIST (insn, eh_stack); + break; + + case NOTE_INSN_EH_REGION_END: + /* Too many end notes. */ + if (eh_stack == NULL_RTX) + abort (); + /* Mismatched nesting. */ + if (NOTE_EH_HANDLER (XEXP (eh_stack, 0)) != NOTE_EH_HANDLER (insn)) + abort (); + tmp = eh_stack; + eh_stack = XEXP (eh_stack, 1); + free_INSN_LIST_node (tmp); + break; + + case NOTE_INSN_BLOCK_BEG: + /* By now, all notes indicating lexical blocks should have + NOTE_BLOCK filled in. */ + if (NOTE_BLOCK (insn) == NULL_TREE) + abort (); + block_stack = alloc_INSN_LIST (insn, block_stack); + break; + + case NOTE_INSN_BLOCK_END: + /* Too many end notes. */ + if (block_stack == NULL_RTX) + abort (); + /* Mismatched nesting. */ + if (NOTE_BLOCK (XEXP (block_stack, 0)) != NOTE_BLOCK (insn)) + abort (); + tmp = block_stack; + block_stack = XEXP (block_stack, 1); + free_INSN_LIST_node (tmp); + + /* Scan back to see if there are any non-note instructions + between INSN and the beginning of this block. If not, + then there is no PC range in the generated code that will + actually be in this block, so there's no point in + remembering the existence of the block. */ + for (tmp = PREV_INSN (insn); tmp; tmp = PREV_INSN (tmp)) + { + /* This block contains a real instruction. Note that we + don't include labels; if the only thing in the block + is a label, then there are still no PC values that + lie within the block. */ + if (INSN_P (tmp)) + break; + + /* We're only interested in NOTEs. */ + if (GET_CODE (tmp) != NOTE) + continue; + + if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_BEG) + { + /* We just verified that this BLOCK matches us with + the block_stack check above. Never delete the + BLOCK for the outermost scope of the function; we + can refer to names from that scope even if the + block notes are messed up. */ + if (! is_body_block (NOTE_BLOCK (insn)) + && (*debug_hooks->ignore_block) (NOTE_BLOCK (insn))) + { + remove_insn (tmp); + remove_insn (insn); + } + break; + } + else if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_END) + /* There's a nested block. We need to leave the + current block in place since otherwise the debugger + wouldn't be able to show symbols from our block in + the nested block. */ + break; + } + } + } + + /* Too many begin notes. */ + if (block_stack || eh_stack) + abort (); +} + /* Emit insn(s) of given code and pattern at a specified place within the doubly-linked list. @@ -3713,7 +4036,10 @@ emit_insn_before_noloc (rtx x, rtx before) rtx last = before; rtx insn; - gcc_assert (before); +#ifdef ENABLE_RTL_CHECKING + if (before == NULL_RTX) + abort (); +#endif if (x == NULL_RTX) return last; @@ -3738,7 +4064,7 @@ emit_insn_before_noloc (rtx x, rtx before) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - gcc_unreachable (); + abort (); break; #endif @@ -3759,7 +4085,10 @@ emit_jump_insn_before_noloc (rtx x, rtx before) { rtx insn, last = NULL_RTX; - gcc_assert (before); +#ifdef ENABLE_RTL_CHECKING + if (before == NULL_RTX) + abort (); +#endif switch (GET_CODE (x)) { @@ -3781,7 +4110,7 @@ emit_jump_insn_before_noloc (rtx x, rtx before) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - gcc_unreachable (); + abort (); break; #endif @@ -3802,7 +4131,10 @@ emit_call_insn_before_noloc (rtx x, rtx before) { rtx last = NULL_RTX, insn; - gcc_assert (before); +#ifdef ENABLE_RTL_CHECKING + if (before == NULL_RTX) + abort (); +#endif switch (GET_CODE (x)) { @@ -3824,7 +4156,7 @@ emit_call_insn_before_noloc (rtx x, rtx before) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - gcc_unreachable (); + abort (); break; #endif @@ -3874,9 +4206,7 @@ emit_note_before (int subtype, rtx before) { rtx note = rtx_alloc (NOTE); INSN_UID (note) = cur_insn_uid++; -#ifndef USE_MAPPED_LOCATION NOTE_SOURCE_FILE (note) = 0; -#endif NOTE_LINE_NUMBER (note) = subtype; BLOCK_FOR_INSN (note) = NULL; @@ -3896,14 +4226,14 @@ emit_insn_after_1 (rtx first, rtx after) rtx after_after; basic_block bb; - if (!BARRIER_P (after) + if (GET_CODE (after) != BARRIER && (bb = BLOCK_FOR_INSN (after))) { bb->flags |= BB_DIRTY; for (last = first; NEXT_INSN (last); last = NEXT_INSN (last)) - if (!BARRIER_P (last)) + if (GET_CODE (last) != BARRIER) set_block_for_insn (last, bb); - if (!BARRIER_P (last)) + if (GET_CODE (last) != BARRIER) set_block_for_insn (last, bb); if (BB_END (bb) == after) BB_END (bb) = last; @@ -3932,7 +4262,10 @@ emit_insn_after_noloc (rtx x, rtx after) { rtx last = after; - gcc_assert (after); +#ifdef ENABLE_RTL_CHECKING + if (after == NULL_RTX) + abort (); +#endif if (x == NULL_RTX) return last; @@ -3950,7 +4283,7 @@ emit_insn_after_noloc (rtx x, rtx after) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - gcc_unreachable (); + abort (); break; #endif @@ -3988,7 +4321,10 @@ emit_jump_insn_after_noloc (rtx x, rtx after) { rtx last; - gcc_assert (after); +#ifdef ENABLE_RTL_CHECKING + if (after == NULL_RTX) + abort (); +#endif switch (GET_CODE (x)) { @@ -4003,7 +4339,7 @@ emit_jump_insn_after_noloc (rtx x, rtx after) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - gcc_unreachable (); + abort (); break; #endif @@ -4024,7 +4360,10 @@ emit_call_insn_after_noloc (rtx x, rtx after) { rtx last; - gcc_assert (after); +#ifdef ENABLE_RTL_CHECKING + if (after == NULL_RTX) + abort (); +#endif switch (GET_CODE (x)) { @@ -4039,7 +4378,7 @@ emit_call_insn_after_noloc (rtx x, rtx after) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - gcc_unreachable (); + abort (); break; #endif @@ -4090,9 +4429,7 @@ emit_note_after (int subtype, rtx after) { rtx note = rtx_alloc (NOTE); INSN_UID (note) = cur_insn_uid++; -#ifndef USE_MAPPED_LOCATION NOTE_SOURCE_FILE (note) = 0; -#endif NOTE_LINE_NUMBER (note) = subtype; BLOCK_FOR_INSN (note) = NULL; add_insn_after (note, after); @@ -4345,7 +4682,7 @@ emit_insn (rtx x) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - gcc_unreachable (); + abort (); break; #endif @@ -4386,7 +4723,7 @@ emit_jump_insn (rtx x) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - gcc_unreachable (); + abort (); break; #endif @@ -4420,7 +4757,7 @@ emit_call_insn (rtx x) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - gcc_unreachable (); + abort (); break; #endif @@ -4470,15 +4807,12 @@ emit_line_note (location_t location) { rtx note; -#ifdef USE_MAPPED_LOCATION - if (location == last_location) - return NULL_RTX; -#else + set_file_and_line_for_stmt (location); + if (location.file && last_location.file && !strcmp (location.file, last_location.file) && location.line == last_location.line) return NULL_RTX; -#endif last_location = location; if (no_line_numbers) @@ -4487,12 +4821,8 @@ emit_line_note (location_t location) return NULL_RTX; } -#ifdef USE_MAPPED_LOCATION - note = emit_note ((int) location); -#else note = emit_note (location.line); NOTE_SOURCE_FILE (note) = location.file; -#endif return note; } @@ -4544,11 +4874,7 @@ emit_note (int note_no) void force_next_line_note (void) { -#ifdef USE_MAPPED_LOCATION - last_location = -1; -#else last_location.line = -1; -#endif } /* Place a note of KIND on insn INSN with DATUM as the datum. If a @@ -4569,7 +4895,8 @@ set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum) means the insn only has one * useful * set). */ if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn)) { - gcc_assert (!note); + if (note) + abort (); return NULL_RTX; } @@ -4596,10 +4923,10 @@ set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum) /* Return an indication of which type of insn should have X as a body. The value is CODE_LABEL, INSN, CALL_INSN or JUMP_INSN. */ -static enum rtx_code +enum rtx_code classify_insn (rtx x) { - if (LABEL_P (x)) + if (GET_CODE (x) == CODE_LABEL) return CODE_LABEL; if (GET_CODE (x) == CALL) return CALL_INSN; @@ -4638,35 +4965,33 @@ emit (rtx x) { enum rtx_code code = classify_insn (x); - switch (code) + if (code == CODE_LABEL) + return emit_label (x); + else if (code == INSN) + return emit_insn (x); + else if (code == JUMP_INSN) { - case CODE_LABEL: - return emit_label (x); - case INSN: - return emit_insn (x); - case JUMP_INSN: - { - rtx insn = emit_jump_insn (x); - if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN) - return emit_barrier (); - return insn; - } - case CALL_INSN: - return emit_call_insn (x); - default: - gcc_unreachable (); + rtx insn = emit_jump_insn (x); + if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN) + return emit_barrier (); + return insn; } + else if (code == CALL_INSN) + return emit_call_insn (x); + else + abort (); } /* Space for free sequence stack entries. */ -static GTY ((deletable)) struct sequence_stack *free_sequence_stack; +static GTY ((deletable (""))) struct sequence_stack *free_sequence_stack; -/* Begin emitting insns to a sequence. If this sequence will contain - something that might cause the compiler to pop arguments to function - calls (because those pops have previously been deferred; see - INHIBIT_DEFER_POP for more details), use do_pending_stack_adjust - before calling this function. That will ensure that the deferred - pops are not accidentally emitted in the middle of this sequence. */ +/* Begin emitting insns to a sequence which can be packaged in an + RTL_EXPR. If this sequence will contain something that might cause + the compiler to pop arguments to function calls (because those + pops have previously been deferred; see INHIBIT_DEFER_POP for more + details), use do_pending_stack_adjust before calling this function. + That will ensure that the deferred pops are not accidentally + emitted in the middle of this sequence. */ void start_sequence (void) @@ -4684,6 +5009,7 @@ start_sequence (void) tem->next = seq_stack; tem->first = first_insn; tem->last = last_insn; + tem->sequence_rtl_expr = seq_rtl_expr; seq_stack = tem; @@ -4691,6 +5017,18 @@ start_sequence (void) last_insn = 0; } +/* Similarly, but indicate that this sequence will be placed in T, an + RTL_EXPR. See the documentation for start_sequence for more + information about how to use this function. */ + +void +start_sequence_for_rtl_expr (tree t) +{ + start_sequence (); + + seq_rtl_expr = t; +} + /* Set up the insn chain starting with FIRST as the current sequence, saving the previously current one. See the documentation for start_sequence for more information about how to use this function. */ @@ -4708,6 +5046,19 @@ push_to_sequence (rtx first) last_insn = last; } +/* Set up the insn chain from a chain stort in FIRST to LAST. */ + +void +push_to_full_sequence (rtx first, rtx last) +{ + start_sequence (); + first_insn = first; + last_insn = last; + /* We really should have the end of the insn chain here. */ + if (last && NEXT_INSN (last)) + abort (); +} + /* Set up the outer-level insn chain as the current sequence, saving the previously current one. */ @@ -4723,6 +5074,7 @@ push_topmost_sequence (void) first_insn = top->first; last_insn = top->last; + seq_rtl_expr = top->sequence_rtl_expr; } /* After emitting to the outer-level insn chain, update the outer-level @@ -4738,6 +5090,7 @@ pop_topmost_sequence (void) top->first = first_insn; top->last = last_insn; + /* ??? Why don't we save seq_rtl_expr here? */ end_sequence (); } @@ -4762,6 +5115,7 @@ end_sequence (void) first_insn = tem->first; last_insn = tem->last; + seq_rtl_expr = tem->sequence_rtl_expr; seq_stack = tem->next; memset (tem, 0, sizeof (*tem)); @@ -4769,6 +5123,17 @@ end_sequence (void) free_sequence_stack = tem; } +/* This works like end_sequence, but records the old sequence in FIRST + and LAST. */ + +void +end_full_sequence (rtx *first, rtx *last) +{ + *first = first_insn; + *last = last_insn; + end_sequence (); +} + /* Return 1 if currently emitting into a sequence. */ int @@ -4779,7 +5144,7 @@ in_sequence_p (void) /* Put the various virtual registers into REGNO_REG_RTX. */ -static void +void init_virtual_regs (struct emit_status *es) { rtx *ptr = es->x_regno_reg_rtx; @@ -4831,6 +5196,7 @@ copy_insn_1 (rtx orig) switch (code) { case REG: + case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -4838,11 +5204,8 @@ copy_insn_1 (rtx orig) case CODE_LABEL: case PC: case CC0: + case ADDRESSOF: return orig; - case CLOBBER: - if (REG_P (XEXP (orig, 0)) && REGNO (XEXP (orig, 0)) < FIRST_PSEUDO_REGISTER) - return orig; - break; case SCRATCH: for (i = 0; i < copy_insn_n_scratches; i++) @@ -4868,18 +5231,20 @@ copy_insn_1 (rtx orig) break; } - /* Copy the various flags, fields, and other information. We assume - that all fields need copying, and then clear the fields that should + copy = rtx_alloc (code); + + /* Copy the various flags, and other information. We assume that + all fields need copying, and then clear the fields that should not be copied. That is the sensible default behavior, and forces us to explicitly document why we are *not* copying a flag. */ - copy = shallow_copy_rtx (orig); + memcpy (copy, orig, RTX_HDR_SIZE); /* We do not copy the USED flag, which is used as a mark bit during walks over the RTL. */ RTX_FLAG (copy, used) = 0; /* We do not copy JUMP, CALL, or FRAME_RELATED for INSNs. */ - if (INSN_P (orig)) + if (GET_RTX_CLASS (code) == 'i') { RTX_FLAG (copy, jump) = 0; RTX_FLAG (copy, call) = 0; @@ -4889,45 +5254,49 @@ copy_insn_1 (rtx orig) format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) - switch (*format_ptr++) - { - case 'e': - if (XEXP (orig, i) != NULL) - XEXP (copy, i) = copy_insn_1 (XEXP (orig, i)); - break; + { + copy->u.fld[i] = orig->u.fld[i]; + switch (*format_ptr++) + { + case 'e': + if (XEXP (orig, i) != NULL) + XEXP (copy, i) = copy_insn_1 (XEXP (orig, i)); + break; - case 'E': - case 'V': - if (XVEC (orig, i) == orig_asm_constraints_vector) - XVEC (copy, i) = copy_asm_constraints_vector; - else if (XVEC (orig, i) == orig_asm_operands_vector) - XVEC (copy, i) = copy_asm_operands_vector; - else if (XVEC (orig, i) != NULL) - { - XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); - for (j = 0; j < XVECLEN (copy, i); j++) - XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j)); - } - break; + case 'E': + case 'V': + if (XVEC (orig, i) == orig_asm_constraints_vector) + XVEC (copy, i) = copy_asm_constraints_vector; + else if (XVEC (orig, i) == orig_asm_operands_vector) + XVEC (copy, i) = copy_asm_operands_vector; + else if (XVEC (orig, i) != NULL) + { + XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); + for (j = 0; j < XVECLEN (copy, i); j++) + XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j)); + } + break; - case 't': - case 'w': - case 'i': - case 's': - case 'S': - case 'u': - case '0': - /* These are left unchanged. */ - break; + case 't': + case 'w': + case 'i': + case 's': + case 'S': + case 'u': + case '0': + /* These are left unchanged. */ + break; - default: - gcc_unreachable (); - } + default: + abort (); + } + } if (code == SCRATCH) { i = copy_insn_n_scratches++; - gcc_assert (i < MAX_RECOG_OPERANDS); + if (i >= MAX_RECOG_OPERANDS) + abort (); copy_insn_scratch_in[i] = orig; copy_insn_scratch_out[i] = copy; } @@ -4969,10 +5338,13 @@ init_emit (void) f->emit = ggc_alloc (sizeof (struct emit_status)); first_insn = NULL; last_insn = NULL; + seq_rtl_expr = NULL; cur_insn_uid = 1; reg_rtx_no = LAST_VIRTUAL_REGISTER + 1; - last_location = UNKNOWN_LOCATION; + last_location.line = 0; + last_location.file = 0; first_label_num = label_num; + last_label_num = 0; seq_stack = NULL; /* Init the tables that describe all the pseudo regs. */ @@ -5025,10 +5397,10 @@ init_emit (void) #endif } -/* Generate a vector constant for mode MODE and constant value CONSTANT. */ +/* Generate the constant 0. */ static rtx -gen_const_vector (enum machine_mode mode, int constant) +gen_const_vector_0 (enum machine_mode mode) { rtx tem; rtvec v; @@ -5038,48 +5410,31 @@ gen_const_vector (enum machine_mode mode, int constant) units = GET_MODE_NUNITS (mode); inner = GET_MODE_INNER (mode); - gcc_assert (!DECIMAL_FLOAT_MODE_P (inner)); - v = rtvec_alloc (units); - /* We need to call this function after we set the scalar const_tiny_rtx - entries. */ - gcc_assert (const_tiny_rtx[constant][(int) inner]); + /* We need to call this function after we to set CONST0_RTX first. */ + if (!CONST0_RTX (inner)) + abort (); for (i = 0; i < units; ++i) - RTVEC_ELT (v, i) = const_tiny_rtx[constant][(int) inner]; + RTVEC_ELT (v, i) = CONST0_RTX (inner); tem = gen_rtx_raw_CONST_VECTOR (mode, v); return tem; } /* Generate a vector like gen_rtx_raw_CONST_VEC, but use the zero vector when - all elements are zero, and the one vector when all elements are one. */ + all elements are zero. */ rtx gen_rtx_CONST_VECTOR (enum machine_mode mode, rtvec v) { - enum machine_mode inner = GET_MODE_INNER (mode); - int nunits = GET_MODE_NUNITS (mode); - rtx x; + rtx inner_zero = CONST0_RTX (GET_MODE_INNER (mode)); int i; - /* Check to see if all of the elements have the same value. */ - x = RTVEC_ELT (v, nunits - 1); - for (i = nunits - 2; i >= 0; i--) - if (RTVEC_ELT (v, i) != x) - break; - - /* If the values are all the same, check to see if we can use one of the - standard constant vectors. */ - if (i == -1) - { - if (x == CONST0_RTX (inner)) - return CONST0_RTX (mode); - else if (x == CONST1_RTX (inner)) - return CONST1_RTX (mode); - } - - return gen_rtx_raw_CONST_VECTOR (mode, v); + for (i = GET_MODE_NUNITS (mode) - 1; i >= 0; i--) + if (RTVEC_ELT (v, i) != inner_zero) + return gen_rtx_raw_CONST_VECTOR (mode, v); + return CONST0_RTX (mode); } /* Create some permanent unique rtl objects shared between all functions. @@ -5116,8 +5471,7 @@ init_emit_once (int line_numbers) word_mode = VOIDmode; double_mode = VOIDmode; - for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); - mode != VOIDmode; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) { if (GET_MODE_BITSIZE (mode) == BITS_PER_UNIT @@ -5129,8 +5483,7 @@ init_emit_once (int line_numbers) word_mode = mode; } - for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); - mode != VOIDmode; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) { if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE @@ -5144,8 +5497,8 @@ init_emit_once (int line_numbers) This must be done at runtime because the register number field is in a union and some compilers can't initialize unions. */ - pc_rtx = gen_rtx_PC (VOIDmode); - cc0_rtx = gen_rtx_CC0 (VOIDmode); + pc_rtx = gen_rtx (PC, VOIDmode); + cc0_rtx = gen_rtx (CC0, VOIDmode); stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM); frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM); if (hard_frame_pointer_rtx == 0) @@ -5178,7 +5531,7 @@ init_emit_once (int line_numbers) /* Create the unique rtx's for certain rtx codes and operand values. */ - /* Don't use gen_rtx_CONST_INT here since gen_rtx_CONST_INT in this case + /* Don't use gen_rtx here since gen_rtx in this case tries to use these variables. */ for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++) const_int_rtx[i + MAX_SAVED_CONST_INT] = @@ -5199,7 +5552,7 @@ init_emit_once (int line_numbers) REAL_VALUE_FROM_INT (dconstm2, -2, -1, double_mode); dconsthalf = dconst1; - SET_REAL_EXP (&dconsthalf, REAL_EXP (&dconsthalf) - 1); + dconsthalf.exp--; real_arithmetic (&dconstthird, RDIV_EXPR, &dconst1, &dconst3); @@ -5215,22 +5568,14 @@ init_emit_once (int line_numbers) REAL_VALUE_TYPE *r = (i == 0 ? &dconst0 : i == 1 ? &dconst1 : &dconst2); - for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); - mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) - const_tiny_rtx[i][(int) mode] = - CONST_DOUBLE_FROM_REAL_VALUE (*r, mode); - - for (mode = GET_CLASS_NARROWEST_MODE (MODE_DECIMAL_FLOAT); - mode != VOIDmode; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) const_tiny_rtx[i][(int) mode] = CONST_DOUBLE_FROM_REAL_VALUE (*r, mode); const_tiny_rtx[i][(int) VOIDmode] = GEN_INT (i); - for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); - mode != VOIDmode; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) const_tiny_rtx[i][(int) mode] = GEN_INT (i); @@ -5243,18 +5588,12 @@ init_emit_once (int line_numbers) for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - { - const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); - const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1); - } + const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode); for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - { - const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); - const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1); - } + const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode); for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i) if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC) @@ -5295,6 +5634,27 @@ init_emit_once (int line_numbers) pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); } +/* Query and clear/ restore no_line_numbers. This is used by the + switch / case handling in stmt.c to give proper line numbers in + warnings about unreachable code. */ + +int +force_line_numbers (void) +{ + int old = no_line_numbers; + + no_line_numbers = 0; + if (old) + force_next_line_note (); + return old; +} + +void +restore_line_number_status (int old_value) +{ + no_line_numbers = old_value; +} + /* Produce exact duplicate of insn INSN after AFTER. Care updating of libcall regions if present. */ @@ -5324,7 +5684,7 @@ emit_copy_of_insn_after (rtx insn, rtx after) break; default: - gcc_unreachable (); + abort (); } /* Update LABEL_NUSES. */ @@ -5332,11 +5692,6 @@ emit_copy_of_insn_after (rtx insn, rtx after) INSN_LOCATOR (new) = INSN_LOCATOR (insn); - /* If the old insn is frame related, then so is the new one. This is - primarily needed for IA-64 unwind info which marks epilogue insns, - which may be duplicated by the basic block reordering code. */ - RTX_FRAME_RELATED_P (new) = RTX_FRAME_RELATED_P (insn); - /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will make them. */ for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) @@ -5367,15 +5722,4 @@ emit_copy_of_insn_after (rtx insn, rtx after) return new; } -static GTY((deletable)) rtx hard_reg_clobbers [NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER]; -rtx -gen_hard_reg_clobber (enum machine_mode mode, unsigned int regno) -{ - if (hard_reg_clobbers[mode][regno]) - return hard_reg_clobbers[mode][regno]; - else - return (hard_reg_clobbers[mode][regno] = - gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (mode, regno))); -} - #include "gt-emit-rtl.h" diff --git a/contrib/gcc/f/BUGS b/contrib/gcc/f/BUGS deleted file mode 100644 index acfe4ab..0000000 --- a/contrib/gcc/f/BUGS +++ /dev/null @@ -1,130 +0,0 @@ -_Note:_ This file is automatically generated from the files -`bugs0.texi' and `bugs.texi'. `BUGS' is _not_ a source file, although -it is normally included within source distributions. - - This file lists known bugs in the GCC-3.2 version of the GNU Fortran -compiler. Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002 Free -Software Foundation, Inc. You may copy, distribute, and modify it -freely as long as you preserve this copyright notice and permission -notice. - -Known Bugs In GNU Fortran -************************* - - This section identifies bugs that `g77' _users_ might run into in -the GCC-3.2 version of `g77'. This includes bugs that are actually in -the `gcc' back end (GBE) or in `libf2c', because those sets of code are -at least somewhat under the control of (and necessarily intertwined -with) `g77', so it isn't worth separating them out. - - For information on bugs in _other_ versions of `g77', see -`gcc/gcc/f/NEWS'. There, lists of bugs fixed in various versions of -`g77' can help determine what bugs existed in prior versions. - - An online, "live" version of this document (derived directly from -the mainline, development version of `g77' within `gcc') is available -via `http://www.gnu.org/software/gcc/onlinedocs/g77/Trouble.html'. -Follow the "Known Bugs" link. - - The following information was last updated on 2002-02-01: - - * `g77' fails to warn about use of a "live" iterative-DO variable as - an implied-DO variable in a `WRITE' or `PRINT' statement (although - it does warn about this in a `READ' statement). - - * Something about `g77''s straightforward handling of label - references and definitions sometimes prevents the GBE from - unrolling loops. Until this is solved, try inserting or removing - `CONTINUE' statements as the terminal statement, using the `END DO' - form instead, and so on. - - * Some confusion in diagnostics concerning failing `INCLUDE' - statements from within `INCLUDE''d or `#include''d files. - - * `g77' assumes that `INTEGER(KIND=1)' constants range from `-2**31' - to `2**31-1' (the range for two's-complement 32-bit values), - instead of determining their range from the actual range of the - type for the configuration (and, someday, for the constant). - - Further, it generally doesn't implement the handling of constants - very well in that it makes assumptions about the configuration - that it no longer makes regarding variables (types). - - Included with this item is the fact that `g77' doesn't recognize - that, on IEEE-754/854-compliant systems, `0./0.' should produce a - NaN and no warning instead of the value `0.' and a warning. - - * `g77' uses way too much memory and CPU time to process large - aggregate areas having any initialized elements. - - For example, `REAL A(1000000)' followed by `DATA A(1)/1/' takes up - way too much time and space, including the size of the generated - assembler file. - - Version 0.5.18 improves cases like this--specifically, cases of - _sparse_ initialization that leave large, contiguous areas - uninitialized--significantly. However, even with the - improvements, these cases still require too much memory and CPU - time. - - (Version 0.5.18 also improves cases where the initial values are - zero to a much greater degree, so if the above example ends with - `DATA A(1)/0/', the compile-time performance will be about as good - as it will ever get, aside from unrelated improvements to the - compiler.) - - Note that `g77' does display a warning message to notify the user - before the compiler appears to hang. - - * When debugging, after starting up the debugger but before being - able to see the source code for the main program unit, the user - must currently set a breakpoint at `MAIN__' (or `MAIN___' or - `MAIN_' if `MAIN__' doesn't exist) and run the program until it - hits the breakpoint. At that point, the main program unit is - activated and about to execute its first executable statement, but - that's the state in which the debugger should start up, as is the - case for languages like C. - - * Debugging `g77'-compiled code using debuggers other than `gdb' is - likely not to work. - - Getting `g77' and `gdb' to work together is a known - problem--getting `g77' to work properly with other debuggers, for - which source code often is unavailable to `g77' developers, seems - like a much larger, unknown problem, and is a lower priority than - making `g77' and `gdb' work together properly. - - On the other hand, information about problems other debuggers have - with `g77' output might make it easier to properly fix `g77', and - perhaps even improve `gdb', so it is definitely welcome. Such - information might even lead to all relevant products working - together properly sooner. - - * `g77' doesn't work perfectly on 64-bit configurations such as the - Digital Semiconductor ("DEC") Alpha. - - This problem is largely resolved as of version 0.5.23. - - * `g77' currently inserts needless padding for things like `COMMON - A,IPAD' where `A' is `CHARACTER*1' and `IPAD' is `INTEGER(KIND=1)' - on machines like x86, because the back end insists that `IPAD' be - aligned to a 4-byte boundary, but the processor has no such - requirement (though it is usually good for performance). - - The `gcc' back end needs to provide a wider array of - specifications of alignment requirements and preferences for - targets, and front ends like `g77' should take advantage of this - when it becomes available. - - * The `libf2c' routines that perform some run-time arithmetic on - `COMPLEX' operands were modified circa version 0.5.20 of `g77' to - work properly even in the presence of aliased operands. - - While the `g77' and `netlib' versions of `libf2c' differ on how - this is accomplished, the main differences are that we believe the - `g77' version works properly even in the presence of _partially_ - aliased operands. - - However, these modifications have reduced performance on targets - such as x86, due to the extra copies of operands involved. - diff --git a/contrib/gcc/f/NEWS b/contrib/gcc/f/NEWS deleted file mode 100644 index cc73668..0000000 --- a/contrib/gcc/f/NEWS +++ /dev/null @@ -1,531 +0,0 @@ -_Note:_ This file is automatically generated from the files -`news0.texi' and `news.texi'. `NEWS' is _not_ a source file, although -it is normally included within source distributions. - - This file lists news about the GCC-3.2 version (and some other -versions) of the GNU Fortran compiler. Copyright (C) -1995,1996,1997,1998,1999,2000,2001,2002 Free Software Foundation, Inc. -You may copy, distribute, and modify it freely as long as you preserve -this copyright notice and permission notice. - -News About GNU Fortran -********************** - - Changes made to recent versions of GNU Fortran are listed below, -with the most recent version first. - - The changes are generally listed in order: - - 1. Code-generation and run-time-library bug-fixes - - 2. Compiler and run-time-library crashes involving valid code that - have been fixed - - 3. New features - - 4. Fixes and enhancements to existing features - - 5. New diagnostics - - 6. Internal improvements - - 7. Miscellany - - This order is not strict--for example, some items involve a -combination of these elements. - - Note that two variants of `g77' are tracked below. The `egcs' -variant is described vis-a-vis previous versions of `egcs' and/or an -official FSF version, as appropriate. Note that all such variants are -obsolete _as of July 1999_ - the information is retained here only for -its historical value. - - Therefore, `egcs' versions sometimes have multiple listings to help -clarify how they differ from other versions, though this can make -getting a complete picture of what a particular `egcs' version contains -somewhat more difficult. - - An online, "live" version of this document (derived directly from -the mainline, development version of `g77' within `gcc') is available at -`http://www.gnu.org/software/gcc/onlinedocs/g77/News.html'. - - The following information was last updated on 2002-10-28: - -In `GCC' 3.2 versus `GCC' 3.1: -============================== - - * Problem Reports fixed (in chronological order of submission): - `8308' - gcc-3.x does not compile files with suffix .r (RATFOR) [Fixed - in 3.2.1] - -In `GCC' 3.1 (formerly known as g77-0.5.27) versus `GCC' 3.0: -============================================================= - - * Problem Reports fixed (in chronological order of submission): - `947' - Data statement initialization with subscript of kind INTEGER*2 - - `3743' - Reference to intrinsic `ISHFT' invalid - - `3807' - Function BESJN(integer,double) problems - - `3957' - g77 -pipe -xf77-cpp-input sends output to stdout - - `4279' - g77 -h" gives bogus output - - `4730' - ICE on valid input using CALL EXIT(%VAL(...)) - - `4752' - g77 -v -c -xf77-version /dev/null -xnone causes ice - - `4885' - BACKSPACE example that doesn't work as of gcc/g77-3.0.x - - `5122' - g77 rejects accepted use of INTEGER*2 as type of DATA - statement loop index - - `5397' - ICE on compiling source with 540 000 000 REAL array - - `5473' - ICE on BESJN(integer*8,real) - - `5837' - bug in loop unrolling - - * `g77' now has its man page generated from the texinfo - documentation, to guarantee that it remains up to date. - - * `g77' used to reject the following program on 32-bit targets: - PROGRAM PROG - DIMENSION A(140 000 000) - END - with the message: - prog.f: In program `prog': - prog.f:2: - DIMENSION A(140 000 000) - ^ - Array `a' at (^) is too large to handle - because 140 000 000 REALs is larger than the largest bit-extent - that can be expressed in 32 bits. However, bit-sizes never play a - role after offsets have been converted to byte addresses. - Therefore this check has been removed, and the limit is now 2 - Gbyte of memory (around 530 000 000 REALs). Note: On GNU/Linux - systems one has to compile programs that occupy more than 1 Gbyte - statically, i.e. `g77 -static ...'. - - * Based on work done by Juergen Pfeifer (<juergen.pfeifer@gmx.net>) - libf2c is now a shared library. One can still link in all objects - with the program by specifying the `-static' option. - - * Robert Anderson (<rwa@alumni.princeton.edu>) thought up a two line - change that enables g77 to compile such code as: - SUBROUTINE SUB(A, N) - DIMENSION N(2) - DIMENSION A(N(1),N(2)) - A(1,1) = 1. - END - Note the use of array elements in the bounds of the adjustable - array A. - - * George Helffrich (<george@geo.titech.ac.jp>) implemented a change - in substring index checking (when specifying `-fbounds-check') - that permits the use of zero length substrings of the form - `string(1:0)'. - - * Based on code developed by Pedro Vazquez - (<vazquez@penelope.iqm.unicamp.br>), the `libf2c' library is now - able to read and write files larger than 2 Gbyte on 32-bit target - machines, if the operating system supports this. - -In 0.5.26, `GCC' 3.0 versus `GCC' 2.95: -======================================= - - * When a REWIND was issued after a WRITE statement on an unformatted - file, the implicit truncation was performed by copying the - truncated file to /tmp and copying the result back. This has been - fixed by using the `ftruncate' OS function. Thanks go to the - GAMESS developers for bringing this to our attention. - - * Using options `-g', `-ggdb' or `-gdwarf[-2]' (where appropriate - for your target) now also enables debugging information for COMMON - BLOCK and EQUIVALENCE items to be emitted. Thanks go to Andrew - Vaught (<andy@xena.eas.asu.edu>) and George Helffrich - (<george@geology.bristol.ac.uk>) for fixing this longstanding - problem. - - * It is not necessary anymore to use the option `-femulate-complex' - to compile Fortran code using COMPLEX arithmetic, even on 64-bit - machines (like the Alpha). This will improve code generation. - - * INTRINSIC arithmetic functions are now treated as routines that do - not depend on anything but their argument(s). This enables - further instruction scheduling, because it is known that they - cannot read or modify arbitrary locations. - - * Upgrade to `libf2c' as of 2000-12-05. - - This fixes a bug where a namelist containing initialization of - LOGICAL items and a variable starting with T or F would be read - incorrectly. - - * The `TtyNam' intrinsics now set NAME to all spaces (at run time) - if the system has no `ttyname' implementation available. - - * Upgrade to `libf2c' as of 1999-06-28. - - This fixes a bug whereby input to a `NAMELIST' read involving a - repeat count, such as `K(5)=10*3', was not properly handled by - `libf2c'. The first item was written to `K(5)', but the remaining - nine were written elsewhere (still within the array), not - necessarily starting at `K(6)'. - -In 0.5.25, `GCC' 2.95 (`EGCS' 1.2) versus `EGCS' 1.1.2: -======================================================= - - * `g77' no longer generates bad code for assignments, or other - conversions, of `REAL' or `COMPLEX' constant expressions to type - `INTEGER(KIND=2)' (often referred to as `INTEGER*8'). - - For example, `INTEGER*8 J; J = 4E10' now works as documented. - - * `g77' no longer truncates `INTEGER(KIND=2)' (usually `INTEGER*8') - subscript expressions when evaluating array references on systems - with pointers widers than `INTEGER(KIND=1)' (such as Alphas). - - * `g77' no longer generates bad code for an assignment to a - `COMPLEX' variable or array that partially overlaps one or more of - the sources of the same assignment (a very rare construction). It - now assigns through a temporary, in cases where such partial - overlap is deemed possible. - - * `libg2c' (`libf2c') no longer loses track of the file being worked - on during a `BACKSPACE' operation. - - * `libg2c' (`libf2c') fixes a bug whereby input to a `NAMELIST' read - involving a repeat count, such as `K(5)=10*3', was not properly - handled by `libf2c'. The first item was written to `K(5)', but - the remaining nine were written elsewhere (still within the array), - not necessarily starting at `K(6)'. - - * Automatic arrays now seem to be working on HP-UX systems. - - * The `Date' intrinsic now returns the correct result on big-endian - systems. - - * Fix `g77' so it no longer crashes when compiling I/O statements - using keywords that define `INTEGER' values, such as `IOSTAT=J', - where J is other than default `INTEGER' (such as `INTEGER*2'). - Instead, it issues a diagnostic. - - * Fix `g77' so it properly handles `DATA A/RPT*VAL/', where RPT is - not default `INTEGER', such as `INTEGER*2', instead of producing a - spurious diagnostic. Also fix `DATA (A(I),I=1,N)', where `N' is - not default `INTEGER' to work instead of crashing `g77'. - - * The `-ax' option is now obeyed when compiling Fortran programs. - (It is passed to the `f771' driver.) - - * The new `-fbounds-check' option causes `g77' to compile run-time - bounds checks of array subscripts, as well as of substring start - and end points. - - * `libg2c' now supports building as multilibbed library, which - provides better support for systems that require options such as - `-mieee' to work properly. - - * Source file names with the suffixes `.FOR' and `.FPP' now are - recognized by `g77' as if they ended in `.for' and `.fpp', - respectively. - - * The order of arguments to the _subroutine_ forms of the `CTime', - `DTime', `ETime', and `TtyNam' intrinsics has been swapped. The - argument serving as the returned value for the corresponding - function forms now is the _second_ argument, making these - consistent with the other subroutine forms of `libU77' intrinsics. - - * `g77' now warns about a reference to an intrinsic that has an - interface that is not Year 2000 (Y2K) compliant. Also, `libg2c' - has been changed to increase the likelihood of catching references - to the implementations of these intrinsics using the `EXTERNAL' - mechanism (which would avoid the new warnings). - - * `g77' now warns about a reference to a function when the - corresponding _subsequent_ function program unit disagrees with - the reference concerning the type of the function. - - * `-fno-emulate-complex' is now the default option. This should - result in improved performance of code that uses the `COMPLEX' - data type. - - * The `-malign-double' option now reliably aligns _all_ - double-precision variables and arrays on Intel x86 targets. - - * Even without the `-malign-double' option, `g77' reliably aligns - local double-precision variables that are not in `EQUIVALENCE' - areas and not `SAVE''d. - - * `g77' now open-codes ("inlines") division of `COMPLEX' operands - instead of generating a run-time call to the `libf2c' routines - `c_div' or `z_div', unless the `-Os' option is specified. - - * `g77' no longer generates code to maintain `errno', a C-language - concept, when performing operations such as the `SqRt' intrinsic. - - * `g77' developers can temporarily use the `-fflatten-arrays' option - to compare how the compiler handles code generation using C-like - constructs as compared to the Fortran-like method constructs - normally used. - - * A substantial portion of the `g77' front end's code-generation - component was rewritten. It now generates code using facilities - more robustly supported by the `gcc' back end. One effect of this - rewrite is that some codes no longer produce a spurious "label LAB - used before containing binding contour" message. - - * Support for the `-fugly' option has been removed. - - * Improve documentation and indexing, including information on Year - 2000 (Y2K) compliance, and providing more information on internals - of the front end. - - * Upgrade to `libf2c' as of 1999-05-10. - -In 0.5.24 versus 0.5.23: -======================== - - There is no `g77' version 0.5.24 at this time, or planned. 0.5.24 -is the version number designated for bug fixes and, perhaps, some new -features added, to 0.5.23. Version 0.5.23 requires `gcc' 2.8.1, as -0.5.24 was planned to require. - - Due to `EGCS' becoming `GCC' (which is now an acronym for "GNU -Compiler Collection"), and `EGCS' 1.2 becoming officially designated -`GCC' 2.95, there seems to be no need for an actual 0.5.24 release. - - To reduce the confusion already resulting from use of 0.5.24 to -designate `g77' versions within `EGCS' versions 1.0 and 1.1, as well as -in versions of `g77' documentation and notices during that period, -"mainline" `g77' version numbering resumes at 0.5.25 with `GCC' 2.95 -(`EGCS' 1.2), skipping over 0.5.24 as a placeholder version number. - - To repeat, there is no `g77' 0.5.24, but there is now a 0.5.25. -Please remain calm and return to your keypunch units. - -In `EGCS' 1.1.2 versus `EGCS' 1.1.1: -==================================== - - * Fix the `IDate' intrinsic (VXT) (in `libg2c') so the returned year - is in the documented, non-Y2K-compliant range of 0-99, instead of - being returned as 100 in the year 2000. - - * Fix the `Date_and_Time' intrinsic (in `libg2c') to return the - milliseconds value properly in VALUES(8). - - * Fix the `LStat' intrinsic (in `libg2c') to return device-ID - information properly in SARRAY(7). - - * Improve documentation. - -In `EGCS' 1.1.1 versus `EGCS' 1.1: -================================== - - * Fix `libg2c' so it performs an implicit `ENDFILE' operation (as - appropriate) whenever a `REWIND' is done. - - (This bug was introduced in 0.5.23 and `egcs' 1.1 in `g77''s - version of `libf2c'.) - - * Fix `libg2c' so it no longer crashes with a spurious diagnostic - upon doing any I/O following a direct formatted write. - - (This bug was introduced in 0.5.23 and `egcs' 1.1 in `g77''s - version of `libf2c'.) - - * Fix `g77' so it no longer crashes compiling references to the - `Rand' intrinsic on some systems. - - * Fix `g77' portion of installation process so it works better on - some systems (those with shells requiring `else true' clauses on - `if' constructs for the completion code to be set properly). - -In `EGCS' 1.1 versus `EGCS' 1.0.3: -================================== - - * Fix bugs in the `libU77' intrinsic `HostNm' that wrote one byte - beyond the end of its `CHARACTER' argument, and in the `libU77' - intrinsics `GMTime' and `LTime' that overwrote their arguments. - - * Assumed arrays with negative bounds (such as `REAL A(-1:*)') no - longer elicit spurious diagnostics from `g77', even on systems - with pointers having different sizes than integers. - - This bug is not known to have existed in any recent version of - `gcc'. It was introduced in an early release of `egcs'. - - * Valid combinations of `EXTERNAL', passing that external as a dummy - argument without explicitly giving it a type, and, in a subsequent - program unit, referencing that external as an external function - with a different type no longer crash `g77'. - - * `CASE DEFAULT' no longer crashes `g77'. - - * The `-Wunused' option no longer issues a spurious warning about - the "master" procedure generated by `g77' for procedures - containing `ENTRY' statements. - - * Support `FORMAT(I<EXPR>)' when EXPR is a compile-time constant - `INTEGER' expression. - - * Fix `g77' `-g' option so procedures that use `ENTRY' can be - stepped through, line by line, in `gdb'. - - * Allow any `REAL' argument to intrinsics `Second' and `CPU_Time'. - - * Use `tempnam', if available, to open scratch files (as in - `OPEN(STATUS='SCRATCH')') so that the `TMPDIR' environment - variable, if present, is used. - - * `g77''s version of `libf2c' separates out the setting of global - state (such as command-line arguments and signal handling) from - `main.o' into distinct, new library archive members. - - This should make it easier to write portable applications that - have their own (non-Fortran) `main()' routine properly set up the - `libf2c' environment, even when `libf2c' (now `libg2c') is a - shared library. - - * `g77' no longer installs the `f77' command and `f77.1' man page in - the `/usr' or `/usr/local' hierarchy, even if the `f77-install-ok' - file exists in the source or build directory. See the - installation documentation for more information. - - * `g77' no longer installs the `libf2c.a' library and `f2c.h' - include file in the `/usr' or `/usr/local' hierarchy, even if the - `f2c-install-ok' or `f2c-exists-ok' files exist in the source or - build directory. See the installation documentation for more - information. - - * The `libf2c.a' library produced by `g77' has been renamed to - `libg2c.a'. It is installed only in the `gcc' "private" directory - hierarchy, `gcc-lib'. This allows system administrators and users - to choose which version of the `libf2c' library from `netlib' they - wish to use on a case-by-case basis. See the installation - documentation for more information. - - * The `f2c.h' include (header) file produced by `g77' has been - renamed to `g2c.h'. It is installed only in the `gcc' "private" - directory hierarchy, `gcc-lib'. This allows system administrators - and users to choose which version of the include file from - `netlib' they wish to use on a case-by-case basis. See the - installation documentation for more information. - - * The `g77' command now expects the run-time library to be named - `libg2c.a' instead of `libf2c.a', to ensure that a version other - than the one built and installed as part of the same `g77' version - is picked up. - - * During the configuration and build process, `g77' creates - subdirectories it needs only as it needs them. Other cleaning up - of the configuration and build process has been performed as well. - - * `install-info' now used to update the directory of Info - documentation to contain an entry for `g77' (during installation). - - * Some diagnostics have been changed from warnings to errors, to - prevent inadvertent use of the resulting, probably buggy, programs. - These mostly include diagnostics about use of unsupported features - in the `OPEN', `INQUIRE', `READ', and `WRITE' statements, and - about truncations of various sorts of constants. - - * Improve compilation of `FORMAT' expressions so that a null byte is - appended to the last operand if it is a constant. This provides a - cleaner run-time diagnostic as provided by `libf2c' for statements - like `PRINT '(I1', 42'. - - * Improve documentation and indexing. - - * The upgrade to `libf2c' as of 1998-06-18 should fix a variety of - problems, including those involving some uses of the `T' format - specifier, and perhaps some build (porting) problems as well. - -In `EGCS' 1.1 versus `g77' 0.5.23: -================================== - - * Fix a code-generation bug that afflicted Intel x86 targets when - `-O2' was specified compiling, for example, an old version of the - `DNRM2' routine. - - The x87 coprocessor stack was being mismanaged in cases involving - assigned `GOTO' and `ASSIGN'. - - * `g77' no longer produces incorrect code and initial values for - `EQUIVALENCE' and `COMMON' aggregates that, due to "unnatural" - ordering of members vis-a-vis their types, require initial padding. - - * Fix `g77' crash compiling code containing the construct - `CMPLX(0.)' or similar. - - * `g77' no longer crashes when compiling code containing - specification statements such as `INTEGER(KIND=7) PTR'. - - * `g77' no longer crashes when compiling code such as `J = SIGNAL(1, - 2)'. - - * `g77' now treats `%LOC(EXPR)' and `LOC(EXPR)' as "ordinary" - expressions when they are used as arguments in procedure calls. - This change applies only to global (filewide) analysis, making it - consistent with how `g77' actually generates code for these cases. - - Previously, `g77' treated these expressions as denoting special - "pointer" arguments for the purposes of filewide analysis. - - * Fix `g77' crash (or apparently infinite run-time) when compiling - certain complicated expressions involving `COMPLEX' arithmetic - (especially multiplication). - - * Align static double-precision variables and arrays on Intel x86 - targets regardless of whether `-malign-double' is specified. - - Generally, this affects only local variables and arrays having the - `SAVE' attribute or given initial values via `DATA'. - - * The `g77' driver now ensures that `-lg2c' is specified in the link - phase prior to any occurrence of `-lm'. This prevents - accidentally linking to a routine in the SunOS4 `-lm' library when - the generated code wants to link to the one in `libf2c' (`libg2c'). - - * `g77' emits more debugging information when `-g' is used. - - This new information allows, for example, `which __g77_length_a' - to be used in `gdb' to determine the type of the phantom length - argument supplied with `CHARACTER' variables. - - This information pertains to internally-generated type, variable, - and other information, not to the longstanding deficiencies - vis-a-vis `COMMON' and `EQUIVALENCE'. - - * The F90 `Date_and_Time' intrinsic now is supported. - - * The F90 `System_Clock' intrinsic allows the optional arguments - (except for the `Count' argument) to be omitted. - - * Upgrade to `libf2c' as of 1998-06-18. - - * Improve documentation and indexing. - -In previous versions: -===================== - - Information on previous versions is not provided in this -`gcc/gcc/f/NEWS' file, to keep it short. See `gcc/gcc/f/news.texi', or -any of its other derivations (Info, HTML, dvi forms) for such -information. - diff --git a/contrib/gcc/f/g77spec.c b/contrib/gcc/f/g77spec.c index ce1bc69..449f299 100644 --- a/contrib/gcc/f/g77spec.c +++ b/contrib/gcc/f/g77spec.c @@ -19,6 +19,8 @@ along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $FreeBSD$ */ + /* This file contains a filter for the main `gcc' driver, which is replicated for the `g77' driver by adding this filter. The purpose of this filter is to be basically identical to gcc (in that @@ -55,14 +57,23 @@ Boston, MA 02111-1307, USA. */ #ifndef MATH_LIBRARY #define MATH_LIBRARY "-lm" #endif +#ifndef MATH_LIBRARY_PROFILE +#define MATH_LIBRARY_PROFILE "-lm" +#endif #ifndef FORTRAN_INIT #define FORTRAN_INIT "-lfrtbegin" #endif +#ifndef FORTRAN_INIT_PROFILE +#define FORTRAN_INIT_PROFILE "-lfrtbegin" +#endif #ifndef FORTRAN_LIBRARY #define FORTRAN_LIBRARY "-lg2c" #endif +#ifndef FORTRAN_LIBRARY_PROFILE +#define FORTRAN_LIBRARY_PROFILE "-lg2c" +#endif /* Options this driver needs to recognize, not just know how to skip over. */ @@ -82,6 +93,7 @@ typedef enum OPTION_nostdlib, /* Aka --no-standard-libraries, or -nodefaultlibs. */ OPTION_o, /* Aka --output. */ + OPTION_p, /* Aka --profile. */ OPTION_S, /* Aka --assemble. */ OPTION_syntax_only, /* -fsyntax-only. */ OPTION_v, /* Aka --verbose. */ @@ -143,6 +155,9 @@ lookup_option (Option *xopt, int *xskip, const char **xarg, const char *text) opt = OPTION_L, arg = text + 2; else if (text[1] == 'o') opt = OPTION_o; + else if ((text[1] == 'p') && (text[2] == '\0') + || (text[1] == 'p') && (text[2] == 'g') && (text[3] == '\0')) + opt = OPTION_p; else if ((text[1] == 'S') && (text[2] == '\0')) opt = OPTION_S, skip = 0; else if (text[1] == 'V') @@ -264,6 +279,9 @@ lang_specific_driver (int *in_argc, const char *const **in_argv, /* By default, we throw on the math library if we have one. */ int need_math = (MATH_LIBRARY[0] != '\0'); + /* If non-zero, the user gave us the `-p' or `-pg' flag. */ + int saw_profile_flag = 0; + /* The number of input and output files in the incoming arg list. */ int n_infiles = 0; int n_outfiles = 0; @@ -332,6 +350,11 @@ lang_specific_driver (int *in_argc, const char *const **in_argv, ++n_outfiles; break; + case OPTION_p: + saw_profile_flag = 1; + library = FORTRAN_LIBRARY_PROFILE; + break; + case OPTION_v: verbose = 1; break; @@ -406,7 +429,7 @@ or type the command `info -f g77 Copying'.\n\ /* Not a filename or library. */ if (saw_library == 1 && need_math) /* -l<library>. */ - append_arg (MATH_LIBRARY); + append_arg (saw_profile_flag ? MATH_LIBRARY_PROFILE : MATH_LIBRARY); saw_library = 0; @@ -453,10 +476,12 @@ or type the command `info -f g77 Copying'.\n\ { if (0 == use_init) { - append_arg (FORTRAN_INIT); + append_arg (saw_profile_flag ? FORTRAN_INIT_PROFILE + : FORTRAN_INIT); use_init = 1; } - append_arg (FORTRAN_LIBRARY); + append_arg (saw_profile_flag ? FORTRAN_LIBRARY_PROFILE + : FORTRAN_LIBRARY); } } else if (strcmp (argv[i], FORTRAN_LIBRARY) == 0) @@ -464,7 +489,8 @@ or type the command `info -f g77 Copying'.\n\ else { /* Other library, or filename. */ if (saw_library == 1 && need_math) - append_arg (MATH_LIBRARY); + append_arg (saw_profile_flag ? MATH_LIBRARY_PROFILE + : MATH_LIBRARY); saw_library = 0; } } @@ -483,13 +509,14 @@ or type the command `info -f g77 Copying'.\n\ case 0: if (0 == use_init) { - append_arg (FORTRAN_INIT); + append_arg (saw_profile_flag ? FORTRAN_INIT_PROFILE + : FORTRAN_INIT); use_init = 1; } append_arg (library); case 1: if (need_math) - append_arg (MATH_LIBRARY); + append_arg (saw_profile_flag ? MATH_LIBRARY_PROFILE : MATH_LIBRARY); default: break; } diff --git a/contrib/gcc/final.c b/contrib/gcc/final.c index d64f0c3..dd5b64e 100644 --- a/contrib/gcc/final.c +++ b/contrib/gcc/final.c @@ -1,7 +1,6 @@ /* Convert RTL to assembler code and output it, for GNU compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -17,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ /* This is the final pass of the compiler. It looks at the rtl code for a function and outputs assembler code. @@ -72,10 +71,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "debug.h" #include "expr.h" #include "cfglayout.h" -#include "tree-pass.h" -#include "timevar.h" -#include "cgraph.h" -#include "coverage.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data @@ -90,10 +85,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "dbxout.h" #endif -#ifdef SDB_DEBUGGING_INFO -#include "sdbout.h" -#endif - /* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a null default for it to save conditionalization later. */ #ifndef CC_STATUS_INIT @@ -114,6 +105,12 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #define JUMP_TABLES_IN_TEXT_SECTION 0 #endif +#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP) +#define HAVE_READONLY_DATA_SECTION 1 +#else +#define HAVE_READONLY_DATA_SECTION 0 +#endif + /* Bitflags used by final_scan_insn. */ #define SEEN_BB 1 #define SEEN_NOTE 2 @@ -135,13 +132,10 @@ static int high_function_linenum; /* Filename of last NOTE. */ static const char *last_filename; -/* Whether to force emission of a line note before the next insn. */ -static bool force_source_line = false; - -extern const int length_unit_log; /* This is defined in insn-attrtab.c. */ +extern int length_unit_log; /* This is defined in insn-attrtab.c. */ /* Nonzero while outputting an `asm' with operands. - This means that inconsistencies are the user's fault, so don't die. + This means that inconsistencies are the user's fault, so don't abort. The precise value is the insn being output, to pass to error_for_asm. */ rtx this_is_asm_operands; @@ -380,11 +374,10 @@ init_insn_lengths (void) } /* Obtain the current length of an insn. If branch shortening has been done, - get its actual length. Otherwise, use FALLBACK_FN to calculate the - length. */ -static inline int -get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED, - int (*fallback_fn) (rtx) ATTRIBUTE_UNUSED) + get its actual length. Otherwise, get its maximum length. */ + +int +get_attr_length (rtx insn ATTRIBUTE_UNUSED) { #ifdef HAVE_ATTR_length rtx body; @@ -402,7 +395,7 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED, return 0; case CALL_INSN: - length = fallback_fn (insn); + length = insn_default_length (insn); break; case JUMP_INSN: @@ -413,7 +406,7 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED, ADDR_VEC_ALIGN. */ } else - length = fallback_fn (insn); + length = insn_default_length (insn); break; case INSN: @@ -422,12 +415,12 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED, return 0; else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) - length = asm_insn_count (body) * fallback_fn (insn); + length = asm_insn_count (body) * insn_default_length (insn); else if (GET_CODE (body) == SEQUENCE) for (i = 0; i < XVECLEN (body, 0); i++) length += get_attr_length (XVECEXP (body, 0, i)); else - length = fallback_fn (insn); + length = insn_default_length (insn); break; default: @@ -440,26 +433,8 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED, return length; #else /* not HAVE_ATTR_length */ return 0; -#define insn_default_length 0 -#define insn_min_length 0 #endif /* not HAVE_ATTR_length */ } - -/* Obtain the current length of an insn. If branch shortening has been done, - get its actual length. Otherwise, get its maximum length. */ -int -get_attr_length (rtx insn) -{ - return get_attr_length_1 (insn, insn_default_length); -} - -/* Obtain the current length of an insn. If branch shortening has been done, - get its actual length. Otherwise, get its minimum length. */ -int -get_attr_min_length (rtx insn) -{ - return get_attr_length_1 (insn, insn_min_length); -} /* Code to handle alignment inside shorten_branches. */ @@ -650,7 +625,7 @@ insn_current_reference_address (rtx branch) seq = NEXT_INSN (PREV_INSN (branch)); seq_uid = INSN_UID (seq); - if (!JUMP_P (branch)) + if (GET_CODE (branch) != JUMP_INSN) /* This can happen for example on the PA; the objective is to know the offset to address something in front of the start of the function. Thus, we can treat it like a backward branch. @@ -676,10 +651,7 @@ insn_current_reference_address (rtx branch) } #endif /* HAVE_ATTR_length */ -/* Compute branch alignments based on frequency information in the - CFG. */ - -static unsigned int +void compute_alignments (void) { int log, max_skip, max_log; @@ -693,26 +665,26 @@ compute_alignments (void) max_labelno = max_label_num (); min_labelno = get_first_label_num (); - label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1); + label_align = xcalloc (max_labelno - min_labelno + 1, + sizeof (struct label_alignment)); /* If not optimizing or optimizing for size, don't assign any alignments. */ if (! optimize || optimize_size) - return 0; + return; FOR_EACH_BB (bb) { rtx label = BB_HEAD (bb); int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0; edge e; - edge_iterator ei; - if (!LABEL_P (label) + if (GET_CODE (label) != CODE_LABEL || probably_never_executed_bb_p (bb)) continue; max_log = LABEL_ALIGN (label); max_skip = LABEL_ALIGN_MAX_SKIP; - FOR_EACH_EDGE (e, ei, bb->preds) + for (e = bb->pred; e; e = e->pred_next) { if (e->flags & EDGE_FALLTHRU) has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e); @@ -760,26 +732,7 @@ compute_alignments (void) LABEL_TO_ALIGNMENT (label) = max_log; LABEL_TO_MAX_SKIP (label) = max_skip; } - return 0; } - -struct tree_opt_pass pass_compute_alignments = -{ - NULL, /* name */ - NULL, /* gate */ - compute_alignments, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - 0, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ - 0 /* letter */ -}; - /* Make a pass over all insns and compute their actual lengths by shortening any branches of variable length if possible. */ @@ -814,10 +767,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) /* Compute maximum UID and allocate label_align / uid_shuid. */ max_uid = get_max_uid (); - /* Free uid_shuid before reallocating it. */ - free (uid_shuid); - - uid_shuid = XNEWVEC (int, max_uid); + uid_shuid = xmalloc (max_uid * sizeof *uid_shuid); if (max_labelno != max_label_num ()) { @@ -833,9 +783,10 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) label_align = xrealloc (label_align, n_labels * sizeof (struct label_alignment)); - /* Range of labels grows monotonically in the function. Failing here + /* Range of labels grows monotonically in the function. Abort here means that the initialization of array got lost. */ - gcc_assert (n_old_labels <= n_labels); + if (n_old_labels > n_labels) + abort (); memset (label_align + n_old_labels, 0, (n_labels - n_old_labels) * sizeof (struct label_alignment)); @@ -856,9 +807,14 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) INSN_SHUID (insn) = i++; if (INSN_P (insn)) - continue; - - if (LABEL_P (insn)) + { + /* reorg might make the first insn of a loop being run once only, + and delete the label in front of it. Then we want to apply + the loop alignment to the new label created by reorg, which + is separated by the former loop start insn from the + NOTE_INSN_LOOP_BEG. */ + } + else if (GET_CODE (insn) == CODE_LABEL) { rtx next; @@ -876,12 +832,11 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) max_log = log; max_skip = LABEL_ALIGN_MAX_SKIP; } - next = next_nonnote_insn (insn); + next = NEXT_INSN (insn); /* ADDR_VECs only take room if read-only data goes into the text section. */ - if (JUMP_TABLES_IN_TEXT_SECTION - || readonly_data_section == text_section) - if (next && JUMP_P (next)) + if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) + if (next && GET_CODE (next) == JUMP_INSN) { rtx nextbody = PATTERN (next); if (GET_CODE (nextbody) == ADDR_VEC @@ -900,13 +855,13 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) max_log = 0; max_skip = 0; } - else if (BARRIER_P (insn)) + else if (GET_CODE (insn) == BARRIER) { rtx label; for (label = insn; label && ! INSN_P (label); label = NEXT_INSN (label)) - if (LABEL_P (label)) + if (GET_CODE (label) == CODE_LABEL) { log = LABEL_ALIGN_AFTER_BARRIER (insn); if (max_log < log) @@ -921,20 +876,20 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) #ifdef HAVE_ATTR_length /* Allocate the rest of the arrays. */ - insn_lengths = XNEWVEC (int, max_uid); + insn_lengths = xmalloc (max_uid * sizeof (*insn_lengths)); insn_lengths_max_uid = max_uid; /* Syntax errors can lead to labels being outside of the main insn stream. Initialize insn_addresses, so that we get reproducible results. */ INSN_ADDRESSES_ALLOC (max_uid); - varying_length = XCNEWVEC (char, max_uid); + varying_length = xcalloc (max_uid, sizeof (char)); /* Initialize uid_align. We scan instructions from end to start, and keep in align_tab[n] the last seen insn that does an alignment of at least n+1, i.e. the successor in the alignment chain for an insn that does / has a known alignment of n. */ - uid_align = XCNEWVEC (rtx, max_uid); + uid_align = xcalloc (max_uid, sizeof *uid_align); for (i = MAX_CODE_ALIGN; --i >= 0;) align_tab[i] = NULL_RTX; @@ -943,7 +898,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) { int uid = INSN_UID (seq); int log; - log = (LABEL_P (seq) ? LABEL_TO_ALIGNMENT (seq) : 0); + log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0); uid_align[uid] = align_tab[0]; if (log) { @@ -970,12 +925,13 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) int min_align; addr_diff_vec_flags flags; - if (!JUMP_P (insn) + if (GET_CODE (insn) != JUMP_INSN || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) continue; pat = PATTERN (insn); len = XVECLEN (pat, 1); - gcc_assert (len > 0); + if (len <= 0) + abort (); min_align = MAX_CODE_ALIGN; for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--) { @@ -994,11 +950,10 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) if (min_align > LABEL_TO_ALIGNMENT (lab)) min_align = LABEL_TO_ALIGNMENT (lab); } - XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab); - XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab); + XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab); + XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab); insn_shuid = INSN_SHUID (insn); rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0)); - memset (&flags, 0, sizeof (flags)); flags.min_align = min_align; flags.base_after_vec = rel > insn_shuid; flags.min_after_vec = min > insn_shuid; @@ -1019,7 +974,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) insn_lengths[uid] = 0; - if (LABEL_P (insn)) + if (GET_CODE (insn) == CODE_LABEL) { int log = LABEL_TO_ALIGNMENT (insn); if (log) @@ -1032,8 +987,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid]; - if (NOTE_P (insn) || BARRIER_P (insn) - || LABEL_P (insn)) + if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER + || GET_CODE (insn) == CODE_LABEL) continue; if (INSN_DELETED_P (insn)) continue; @@ -1043,8 +998,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) { /* This only takes room if read-only data goes into the text section. */ - if (JUMP_TABLES_IN_TEXT_SECTION - || readonly_data_section == text_section) + if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) insn_lengths[uid] = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC) * GET_MODE_SIZE (GET_MODE (body))); @@ -1125,7 +1079,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) uid = INSN_UID (insn); - if (LABEL_P (insn)) + if (GET_CODE (insn) == CODE_LABEL) { int log = LABEL_TO_ALIGNMENT (insn); if (log > insn_current_align) @@ -1150,7 +1104,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) INSN_ADDRESSES (uid) = insn_current_address; #ifdef CASE_VECTOR_SHORTEN_MODE - if (optimize && JUMP_P (insn) + if (optimize && GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) { rtx body = PATTERN (insn); @@ -1245,8 +1199,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr, max_addr - rel_addr, body)); - if (JUMP_TABLES_IN_TEXT_SECTION - || readonly_data_section == text_section) + if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) { insn_lengths[uid] = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body))); @@ -1261,7 +1214,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) if (! (varying_length[uid])) { - if (NONJUMP_INSN_P (insn) + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) { int i; @@ -1283,7 +1236,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) continue; } - if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) { int i; @@ -1391,7 +1344,7 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, (*debug_hooks->begin_prologue) (last_linenum, last_filename); -#if defined (DWARF2_UNWIND_INFO) || defined (TARGET_UNWIND_INFO) +#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO) if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG) dwarf2out_begin_prologue (0, NULL); #endif @@ -1410,13 +1363,14 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, #if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue) if (dwarf2out_do_frame ()) - dwarf2out_frame_debug (NULL_RTX, false); + dwarf2out_frame_debug (NULL_RTX); #endif /* If debugging, assign block numbers to all of the blocks in this function. */ if (write_symbols) { + remove_unnecessary_notes (); reemit_insn_block_notes (); number_blocks (current_function_decl); /* We never actually put out begin/end notes for the top-level @@ -1426,7 +1380,7 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, } /* First output the function prologue: code to set up the stack frame. */ - targetm.asm_out.function_prologue (file, get_frame_size ()); + (*targetm.asm_out.function_prologue) (file, get_frame_size ()); /* If the machine represents the prologue as RTL, the profiling code must be emitted when NOTE_INSN_PROLOGUE_END is scanned. */ @@ -1455,23 +1409,23 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) int sval = current_function_returns_struct; rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1); #if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM) - int cxt = cfun->static_chain_decl != NULL; + int cxt = current_function_needs_context; #endif #endif /* ASM_OUTPUT_REG_PUSH */ if (! NO_PROFILE_COUNTERS) { int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE); - switch_to_section (data_section); + data_section (); ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); - targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no); + (*targetm.asm_out.internal_label) (file, "LP", current_function_funcdef_no); assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1); } - switch_to_section (current_function_section ()); + function_section (current_function_decl); #if defined(ASM_OUTPUT_REG_PUSH) - if (sval && svrtx != NULL_RTX && REG_P (svrtx)) + if (sval && svrtx != NULL_RTX && GET_CODE (svrtx) == REG) ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx)); #endif @@ -1502,7 +1456,7 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) #endif #if defined(ASM_OUTPUT_REG_PUSH) - if (sval && svrtx != NULL_RTX && REG_P (svrtx)) + if (sval && svrtx != NULL_RTX && GET_CODE (svrtx) == REG) ASM_OUTPUT_REG_POP (file, REGNO (svrtx)); #endif } @@ -1520,7 +1474,7 @@ final_end_function (void) /* Finally, output the function epilogue: code to restore the stack frame and return to the caller. */ - targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ()); + (*targetm.asm_out.function_epilogue) (asm_out_file, get_frame_size ()); /* And debug output. */ (*debug_hooks->end_epilogue) (last_linenum, last_filename); @@ -1533,10 +1487,18 @@ final_end_function (void) } /* Output assembler code for some insns: all or part of a function. - For description of args, see `final_start_function', above. */ + For description of args, see `final_start_function', above. + + PRESCAN is 1 if we are not really outputting, + just scanning as if we were outputting. + Prescanning deletes and rearranges insns just like ordinary output. + PRESCAN is -2 if we are outputting after having prescanned. + In this case, don't try to delete or rearrange insns + because that has already been done. + Prescanning is done only on certain machines. */ void -final (rtx first, FILE *file, int optimize) +final (rtx first, FILE *file, int optimize, int prescan) { rtx insn; int max_uid = 0; @@ -1552,16 +1514,13 @@ final (rtx first, FILE *file, int optimize) { rtx last = 0; for (insn = first; insn; insn = NEXT_INSN (insn)) - if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0) + if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) { - if (last != 0 -#ifdef USE_MAPPED_LOCATION - && NOTE_SOURCE_LOCATION (insn) == NOTE_SOURCE_LOCATION (last) -#else - && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) - && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last) -#endif - ) + if ((RTX_INTEGRATED_P (insn) + && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0) + || (last != 0 + && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) + && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last))) { delete_insn (insn); /* Use delete_note. */ continue; @@ -1578,7 +1537,7 @@ final (rtx first, FILE *file, int optimize) #ifdef HAVE_cc0 /* If CC tracking across branches is enabled, record the insn which jumps to each branch only reached from one place. */ - if (optimize && JUMP_P (insn)) + if (optimize && GET_CODE (insn) == JUMP_INSN) { rtx lab = JUMP_LABEL (insn); if (lab && LABEL_NUSES (lab) == 1) @@ -1601,14 +1560,16 @@ final (rtx first, FILE *file, int optimize) { /* This can be triggered by bugs elsewhere in the compiler if new insns are created after init_insn_lengths is called. */ - gcc_assert (NOTE_P (insn)); - insn_current_address = -1; + if (GET_CODE (insn) == NOTE) + insn_current_address = -1; + else + abort (); } else insn_current_address = INSN_ADDRESSES (INSN_UID (insn)); #endif /* HAVE_ATTR_length */ - insn = final_scan_insn (insn, file, optimize, 0, &seen); + insn = final_scan_insn (insn, file, optimize, prescan, 0, &seen); } } @@ -1622,11 +1583,12 @@ get_insn_template (int code, rtx insn) case INSN_OUTPUT_FORMAT_MULTI: return insn_data[code].output.multi[which_alternative]; case INSN_OUTPUT_FORMAT_FUNCTION: - gcc_assert (insn); + if (insn == NULL) + abort (); return (*insn_data[code].output.function) (recog_data.operand, insn); default: - gcc_unreachable (); + abort (); } } @@ -1647,7 +1609,7 @@ output_alternate_entry_point (FILE *file, rtx insn) ASM_WEAKEN_LABEL (file, name); #endif case LABEL_GLOBAL_ENTRY: - targetm.asm_out.globalize_label (file, name); + (*targetm.asm_out.globalize_label) (file, name); case LABEL_STATIC_ENTRY: #ifdef ASM_OUTPUT_TYPE_DIRECTIVE ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); @@ -1657,7 +1619,7 @@ output_alternate_entry_point (FILE *file, rtx insn) case LABEL_NORMAL: default: - gcc_unreachable (); + abort (); } } @@ -1677,12 +1639,12 @@ output_alternate_entry_point (FILE *file, rtx insn) rtx final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, - int nopeepholes ATTRIBUTE_UNUSED, int *seen) + int prescan, int nopeepholes ATTRIBUTE_UNUSED, + int *seen) { #ifdef HAVE_cc0 rtx set; #endif - rtx next; insn_counter++; @@ -1694,25 +1656,26 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, switch (GET_CODE (insn)) { case NOTE: + if (prescan > 0) + break; + switch (NOTE_LINE_NUMBER (insn)) { case NOTE_INSN_DELETED: + case NOTE_INSN_LOOP_BEG: + case NOTE_INSN_LOOP_END: + case NOTE_INSN_LOOP_END_TOP_COND: + case NOTE_INSN_LOOP_CONT: + case NOTE_INSN_LOOP_VTOP: case NOTE_INSN_FUNCTION_END: case NOTE_INSN_REPEATED_LINE_NUMBER: case NOTE_INSN_EXPECTED_VALUE: break; - case NOTE_INSN_SWITCH_TEXT_SECTIONS: - in_cold_section_p = !in_cold_section_p; - (*debug_hooks->switch_text_section) (); - switch_to_section (current_function_section ()); - break; - case NOTE_INSN_BASIC_BLOCK: -#ifdef TARGET_UNWIND_INFO - targetm.asm_out.unwind_emit (asm_out_file, insn); +#ifdef IA64_UNWIND_INFO + IA64_UNWIND_EMIT (asm_out_file, insn); #endif - if (flag_debug_asm) fprintf (asm_out_file, "\t%s basic block %d\n", ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index); @@ -1720,7 +1683,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB) { *seen |= SEEN_EMITTED; - force_source_line = true; + last_filename = NULL; } else *seen |= SEEN_BB; @@ -1738,13 +1701,13 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; case NOTE_INSN_PROLOGUE_END: - targetm.asm_out.function_end_prologue (file); + (*targetm.asm_out.function_end_prologue) (file); profile_after_prologue (file); if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE) { *seen |= SEEN_EMITTED; - force_source_line = true; + last_filename = NULL; } else *seen |= SEEN_NOTE; @@ -1752,7 +1715,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; case NOTE_INSN_EPILOGUE_BEG: - targetm.asm_out.function_begin_epilogue (file); + (*targetm.asm_out.function_begin_epilogue) (file); break; case NOTE_INSN_FUNCTION_BEG: @@ -1762,7 +1725,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE) { *seen |= SEEN_EMITTED; - force_source_line = true; + last_filename = NULL; } else *seen |= SEEN_NOTE; @@ -1772,6 +1735,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, case NOTE_INSN_BLOCK_BEG: if (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE + || write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG || write_symbols == VMS_DEBUG) @@ -1793,6 +1757,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, case NOTE_INSN_BLOCK_END: if (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE + || write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG || write_symbols == VMS_DEBUG) @@ -1803,7 +1768,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* End of a symbol-block. */ --block_depth; - gcc_assert (block_depth >= 0); + if (block_depth < 0) + abort (); (*debug_hooks->end_block) (high_block_linenum, n); } @@ -1816,15 +1782,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); break; - case NOTE_INSN_VAR_LOCATION: - (*debug_hooks->var_location) (insn); - break; - case 0: break; default: - gcc_assert (NOTE_LINE_NUMBER (insn) > 0); + if (NOTE_LINE_NUMBER (insn) <= 0) + abort (); break; } break; @@ -1832,7 +1795,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, case BARRIER: #if defined (DWARF2_UNWIND_INFO) if (dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn, false); + dwarf2out_frame_debug (insn); #endif break; @@ -1876,16 +1839,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, insn, and that branch is the only way to reach this label, set the condition codes based on the branch and its predecessor. */ - if (barrier && BARRIER_P (barrier) - && jump && JUMP_P (jump) + if (barrier && GET_CODE (barrier) == BARRIER + && jump && GET_CODE (jump) == JUMP_INSN && (prev = prev_nonnote_insn (jump)) - && NONJUMP_INSN_P (prev)) + && GET_CODE (prev) == INSN) { NOTICE_UPDATE_CC (PATTERN (prev), prev); NOTICE_UPDATE_CC (PATTERN (jump), jump); } } #endif + if (prescan > 0) + break; if (LABEL_NAME (insn)) (*debug_hooks->label) (insn); @@ -1895,11 +1860,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, fputs (ASM_APP_OFF, file); app_on = 0; } - - next = next_nonnote_insn (insn); - if (next != 0 && JUMP_P (next)) + if (NEXT_INSN (insn) != 0 + && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) { - rtx nextbody = PATTERN (next); + rtx nextbody = PATTERN (NEXT_INSN (insn)); /* If this label is followed by a jump-table, make sure we put the label in the read-only section. Also @@ -1917,24 +1881,23 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { int log_align; - switch_to_section (targetm.asm_out.function_rodata_section - (current_function_decl)); + readonly_data_section (); #ifdef ADDR_VEC_ALIGN - log_align = ADDR_VEC_ALIGN (next); + log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn)); #else log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); #endif ASM_OUTPUT_ALIGN (file, log_align); } else - switch_to_section (current_function_section ()); + function_section (current_function_decl); #ifdef ASM_OUTPUT_CASE_LABEL ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), - next); + NEXT_INSN (insn)); #else - targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn)); + (*targetm.asm_out.internal_label) (file, "L", CODE_LABEL_NUMBER (insn)); #endif #endif break; @@ -1943,7 +1906,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, if (LABEL_ALT_ENTRY_P (insn)) output_alternate_entry_point (file, insn); else - targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn)); + (*targetm.asm_out.internal_label) (file, "L", CODE_LABEL_NUMBER (insn)); break; default: @@ -1951,11 +1914,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, rtx body = PATTERN (insn); int insn_code_number; const char *template; + rtx note; -#ifdef HAVE_conditional_execution - /* Reset this early so it is correct for ASM statements. */ - current_insn_predicate = NULL_RTX; -#endif /* An INSN, JUMP_INSN or CALL_INSN. First check for special kinds that recog doesn't recognize. */ @@ -1964,19 +1924,17 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; #ifdef HAVE_cc0 - { - /* If there is a REG_CC_SETTER note on this insn, it means that - the setting of the condition code was done in the delay slot - of the insn that branched here. So recover the cc status - from the insn that set it. */ + /* If there is a REG_CC_SETTER note on this insn, it means that + the setting of the condition code was done in the delay slot + of the insn that branched here. So recover the cc status + from the insn that set it. */ - rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); - if (note) - { - NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0)); - cc_prev_status = cc_status; - } - } + note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); + if (note) + { + NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0)); + cc_prev_status = cc_status; + } #endif /* Detect insns that are really jump-tables @@ -1988,11 +1946,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, int vlen, idx; #endif - if (! JUMP_TABLES_IN_TEXT_SECTION) - switch_to_section (targetm.asm_out.function_rodata_section - (current_function_decl)); - else - switch_to_section (current_function_section ()); + if (prescan > 0) + break; if (app_on) { @@ -2006,7 +1961,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #ifdef ASM_OUTPUT_ADDR_VEC ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body); #else - gcc_unreachable (); + abort (); #endif } else @@ -2014,7 +1969,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #ifdef ASM_OUTPUT_ADDR_DIFF_VEC ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body); #else - gcc_unreachable (); + abort (); #endif } #else @@ -2027,7 +1982,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, ASM_OUTPUT_ADDR_VEC_ELT (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); #else - gcc_unreachable (); + abort (); #endif } else @@ -2039,7 +1994,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0))); #else - gcc_unreachable (); + abort (); #endif } } @@ -2050,7 +2005,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #endif #endif - switch_to_section (current_function_section ()); + function_section (current_function_decl); break; } @@ -2067,6 +2022,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* There's no telling what that did to the condition codes. */ CC_STATUS_INIT; + if (prescan > 0) + break; if (string[0]) { @@ -2089,10 +2046,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* There's no telling what that did to the condition codes. */ CC_STATUS_INIT; + if (prescan > 0) + break; /* Get out the operand values. */ string = decode_asm_operands (body, ops, NULL, NULL, NULL); - /* Inhibit dieing on what would otherwise be compiler bugs. */ + /* Inhibit aborts on what would otherwise be compiler bugs. */ insn_noperands = noperands; this_is_asm_operands = insn; @@ -2115,7 +2074,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; } - if (app_on) + if (prescan <= 0 && app_on) { fputs (ASM_APP_OFF, file); app_on = 0; @@ -2125,7 +2084,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { /* A delayed-branch sequence */ int i; + rtx next; + if (prescan > 0) + break; final_sequence = body; /* Record the delay slots' frame information before the branch. @@ -2133,7 +2095,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #if defined (DWARF2_UNWIND_INFO) if (dwarf2out_do_frame ()) for (i = 1; i < XVECLEN (body, 0); i++) - dwarf2out_frame_debug (XVECEXP (body, 0, i), false); + dwarf2out_frame_debug (XVECEXP (body, 0, i)); #endif /* The first insn in this SEQUENCE might be a JUMP_INSN that will @@ -2141,7 +2103,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, thought unnecessary. If that happens, cancel this sequence and cause that insn to be restored. */ - next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, 1, seen); + next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1, seen); if (next != XVECEXP (body, 0, 1)) { final_sequence = 0; @@ -2155,7 +2117,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* We loop in case any instruction in a delay slot gets split. */ do - insn = final_scan_insn (insn, file, 0, 1, seen); + insn = final_scan_insn (insn, file, 0, prescan, 1, seen); while (insn != next); } #ifdef DBR_OUTPUT_SEQEND @@ -2168,7 +2130,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, called function. Hence we don't preserve any CC-setting actions in these insns and the CC must be marked as being clobbered by the function. */ - if (CALL_P (XVECEXP (body, 0, 0))) + if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN) { CC_STATUS_INIT; } @@ -2226,6 +2188,20 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, } #endif +#ifndef STACK_REGS + /* Don't bother outputting obvious no-ops, even without -O. + This optimization is fast and doesn't interfere with debugging. + Don't do this if the insn is in a delay slot, since this + will cause an improper number of delay insns to be written. */ + if (final_sequence == 0 + && prescan >= 0 + && GET_CODE (insn) == INSN && GET_CODE (body) == SET + && GET_CODE (SET_SRC (body)) == REG + && GET_CODE (SET_DEST (body)) == REG + && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body))) + break; +#endif + #ifdef HAVE_cc0 /* If this is a conditional branch, maybe modify it if the cc's are in a nonstandard state @@ -2233,12 +2209,15 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, do straightforwardly if the cc's were set up normally. */ if (cc_status.flags != 0 - && JUMP_P (insn) + && GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET && SET_DEST (body) == pc_rtx && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE - && COMPARISON_P (XEXP (SET_SRC (body), 0)) - && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx) + && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<' + && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx + /* This is done during prescan; it is not done again + in final scan when prescan has been done. */ + && prescan >= 0) { /* This function may alter the contents of its argument and clear some of the cc_status.flags bits. @@ -2279,7 +2258,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { rtx cond_rtx, then_rtx, else_rtx; - if (!JUMP_P (insn) + if (GET_CODE (insn) != JUMP_INSN && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE) { cond_rtx = XEXP (SET_SRC (set), 0); @@ -2338,16 +2317,14 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, emit them before the peephole. */ if (next != 0 && next != NEXT_INSN (insn)) { - rtx note, prev = PREV_INSN (insn); + rtx prev = PREV_INSN (insn); for (note = NEXT_INSN (insn); note != next; note = NEXT_INSN (note)) - final_scan_insn (note, file, optimize, nopeepholes, seen); + final_scan_insn (note, file, optimize, prescan, nopeepholes, seen); - /* Put the notes in the proper position for a later - rescan. For example, the SH target can do this - when generating a far jump in a delayed branch - sequence. */ + /* In case this is prescan, put the notes + in proper position for later rescan. */ note = NEXT_INSN (insn); PREV_INSN (note) = prev; NEXT_INSN (prev) = note; @@ -2391,6 +2368,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #ifdef HAVE_conditional_execution if (GET_CODE (PATTERN (insn)) == COND_EXEC) current_insn_predicate = COND_EXEC_TEST (PATTERN (insn)); + else + current_insn_predicate = NULL_RTX; #endif #ifdef HAVE_cc0 @@ -2407,8 +2386,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, current_output_insn = debug_insn = insn; #if defined (DWARF2_UNWIND_INFO) - if (CALL_P (insn) && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn, false); + if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ()) + dwarf2out_frame_debug (insn); #endif /* Find the proper template for this insn. */ @@ -2421,7 +2400,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { rtx prev; - gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare); + if (prev_nonnote_insn (insn) != last_ignored_compare) + abort (); /* We have already processed the notes between the setter and the user. Make sure we don't process them again, this is @@ -2431,7 +2411,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, prev != last_ignored_compare; prev = PREV_INSN (prev)) { - if (NOTE_P (prev)) + if (GET_CODE (prev) == NOTE) delete_insn (prev); /* Use delete_note. */ } @@ -2452,41 +2432,55 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* This instruction should have been split in shorten_branches, to ensure that we would have valid length info for the splitees. */ - gcc_unreachable (); + abort (); #endif return new; } -#ifdef TARGET_UNWIND_INFO - /* ??? This will put the directives in the wrong place if - get_insn_template outputs assembly directly. However calling it - before get_insn_template breaks if the insns is split. */ - targetm.asm_out.unwind_emit (asm_out_file, insn); -#endif + if (prescan > 0) + break; +#ifdef IA64_UNWIND_INFO + IA64_UNWIND_EMIT (asm_out_file, insn); +#endif /* Output assembler code from the template. */ + output_asm_insn (template, recog_data.operand); /* If necessary, report the effect that the instruction has on the unwind info. We've already done this for delay slots and call instructions. */ #if defined (DWARF2_UNWIND_INFO) - if (final_sequence == 0 + if (GET_CODE (insn) == INSN #if !defined (HAVE_prologue) && !ACCUMULATE_OUTGOING_ARGS #endif + && final_sequence == 0 && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn, true); + dwarf2out_frame_debug (insn); #endif +#if 0 + /* It's not at all clear why we did this and doing so used to + interfere with tests that used REG_WAS_0 notes, which are + now gone, so let's try with this out. */ + + /* Mark this insn as having been output. */ + INSN_DELETED_P (insn) = 1; +#endif + + /* Emit information for vtable gc. */ + note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX); + current_output_insn = debug_insn = 0; } } return NEXT_INSN (insn); } -/* Return whether a source line note needs to be emitted before INSN. */ +/* Output debugging info to the assembler file FILE + based on the NOTE-insn INSN, assumed to be a line number. */ static bool notice_source_line (rtx insn) @@ -2494,12 +2488,8 @@ notice_source_line (rtx insn) const char *filename = insn_file (insn); int linenum = insn_line (insn); - if (filename - && (force_source_line - || filename != last_filename - || last_linenum != linenum)) + if (filename && (filename != last_filename || last_linenum != linenum)) { - force_source_line = false; last_filename = filename; last_linenum = linenum; high_block_linenum = MAX (last_linenum, high_block_linenum); @@ -2528,7 +2518,7 @@ cleanup_subreg_operands (rtx insn) recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]); else if (GET_CODE (recog_data.operand[i]) == PLUS || GET_CODE (recog_data.operand[i]) == MULT - || MEM_P (recog_data.operand[i])) + || GET_CODE (recog_data.operand[i]) == MEM) recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]); } @@ -2538,7 +2528,7 @@ cleanup_subreg_operands (rtx insn) *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]); else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS || GET_CODE (*recog_data.dup_loc[i]) == MULT - || MEM_P (*recog_data.dup_loc[i])) + || GET_CODE (*recog_data.dup_loc[i]) == MEM) *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]); } } @@ -2554,25 +2544,8 @@ alter_subreg (rtx *xp) /* simplify_subreg does not remove subreg from volatile references. We are required to. */ - if (MEM_P (y)) - { - int offset = SUBREG_BYTE (x); - - /* For paradoxical subregs on big-endian machines, SUBREG_BYTE - contains 0 instead of the proper offset. See simplify_subreg. */ - if (offset == 0 - && GET_MODE_SIZE (GET_MODE (y)) < GET_MODE_SIZE (GET_MODE (x))) - { - int difference = GET_MODE_SIZE (GET_MODE (y)) - - GET_MODE_SIZE (GET_MODE (x)); - if (WORDS_BIG_ENDIAN) - offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - offset += difference % UNITS_PER_WORD; - } - - *xp = adjust_address (y, GET_MODE (x), offset); - } + if (GET_CODE (y) == MEM) + *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x)); else { rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y), @@ -2580,12 +2553,14 @@ alter_subreg (rtx *xp) if (new != 0) *xp = new; - else if (REG_P (y)) + /* Simplify_subreg can't handle some REG cases, but we have to. */ + else if (GET_CODE (y) == REG) { - /* Simplify_subreg can't handle some REG cases, but we have to. */ - unsigned int regno = subreg_regno (x); + unsigned int regno = subreg_hard_regno (x, 1); *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x)); } + else + abort (); } return *xp; @@ -2601,13 +2576,11 @@ walk_alter_subreg (rtx *xp) { case PLUS: case MULT: - case AND: XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1)); break; case MEM: - case ZERO_EXTEND: XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); break; @@ -2736,7 +2709,7 @@ alter_cond (rtx cond) switch (GET_CODE (cond)) { default: - gcc_unreachable (); + abort (); case NE: PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT); @@ -2786,17 +2759,17 @@ alter_cond (rtx cond) In an `asm', it's the user's fault; otherwise, the compiler's fault. */ void -output_operand_lossage (const char *cmsgid, ...) +output_operand_lossage (const char *msgid, ...) { char *fmt_string; char *new_message; const char *pfx_str; va_list ap; - va_start (ap, cmsgid); + va_start (ap, msgid); - pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: "; - asprintf (&fmt_string, "%s%s", pfx_str, _(cmsgid)); + pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: "; + asprintf (&fmt_string, "%s%s", pfx_str, _(msgid)); vasprintf (&new_message, fmt_string, ap); if (this_is_asm_operands) @@ -2847,9 +2820,9 @@ get_mem_expr_from_op (rtx op, int *paddressp) *paddressp = 0; - if (REG_P (op)) + if (GET_CODE (op) == REG) return REG_EXPR (op); - else if (!MEM_P (op)) + else if (GET_CODE (op) != MEM) return 0; if (MEM_EXPR (op) != 0) @@ -2868,8 +2841,8 @@ get_mem_expr_from_op (rtx op, int *paddressp) && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp))) return expr; - while (GET_RTX_CLASS (GET_CODE (op)) == RTX_UNARY - || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH) + while (GET_RTX_CLASS (GET_CODE (op)) == '1' + || GET_RTX_CLASS (GET_CODE (op)) == '2') op = XEXP (op, 0); expr = get_mem_expr_from_op (op, &inner_addressp); @@ -3048,66 +3021,61 @@ output_asm_insn (const char *template, rtx *operands) else if (ISALPHA (*p)) { int letter = *p++; - unsigned long opnum; - char *endptr; - - opnum = strtoul (p, &endptr, 10); + c = atoi (p); - if (endptr == p) - output_operand_lossage ("operand number missing " - "after %%-letter"); - else if (this_is_asm_operands && opnum >= insn_noperands) + if (! ISDIGIT (*p)) + output_operand_lossage ("operand number missing after %%-letter"); + else if (this_is_asm_operands + && (c < 0 || (unsigned int) c >= insn_noperands)) output_operand_lossage ("operand number out of range"); else if (letter == 'l') - output_asm_label (operands[opnum]); + output_asm_label (operands[c]); else if (letter == 'a') - output_address (operands[opnum]); + output_address (operands[c]); else if (letter == 'c') { - if (CONSTANT_ADDRESS_P (operands[opnum])) - output_addr_const (asm_out_file, operands[opnum]); + if (CONSTANT_ADDRESS_P (operands[c])) + output_addr_const (asm_out_file, operands[c]); else - output_operand (operands[opnum], 'c'); + output_operand (operands[c], 'c'); } else if (letter == 'n') { - if (GET_CODE (operands[opnum]) == CONST_INT) + if (GET_CODE (operands[c]) == CONST_INT) fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, - - INTVAL (operands[opnum])); + - INTVAL (operands[c])); else { putc ('-', asm_out_file); - output_addr_const (asm_out_file, operands[opnum]); + output_addr_const (asm_out_file, operands[c]); } } else - output_operand (operands[opnum], letter); + output_operand (operands[c], letter); - if (!opoutput[opnum]) - oporder[ops++] = opnum; - opoutput[opnum] = 1; + if (!opoutput[c]) + oporder[ops++] = c; + opoutput[c] = 1; - p = endptr; - c = *p; + while (ISDIGIT (c = *p)) + p++; } /* % followed by a digit outputs an operand the default way. */ else if (ISDIGIT (*p)) { - unsigned long opnum; - char *endptr; - - opnum = strtoul (p, &endptr, 10); - if (this_is_asm_operands && opnum >= insn_noperands) + c = atoi (p); + if (this_is_asm_operands + && (c < 0 || (unsigned int) c >= insn_noperands)) output_operand_lossage ("operand number out of range"); else - output_operand (operands[opnum], 0); + output_operand (operands[c], 0); - if (!opoutput[opnum]) - oporder[ops++] = opnum; - opoutput[opnum] = 1; + if (!opoutput[c]) + oporder[ops++] = c; + opoutput[c] = 1; - p = endptr; - c = *p; + while (ISDIGIT (c = *p)) + p++; } /* % followed by punctuation: output something for that punctuation character alone, with no operand. @@ -3142,12 +3110,12 @@ output_asm_label (rtx x) if (GET_CODE (x) == LABEL_REF) x = XEXP (x, 0); - if (LABEL_P (x) - || (NOTE_P (x) + if (GET_CODE (x) == CODE_LABEL + || (GET_CODE (x) == NOTE && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL)) ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); else - output_operand_lossage ("'%%l' operand isn't a label"); + output_operand_lossage ("`%%l' operand isn't a label"); assemble_name (asm_out_file, buf); } @@ -3168,8 +3136,11 @@ output_operand (rtx x, int code ATTRIBUTE_UNUSED) if (x && GET_CODE (x) == SUBREG) x = alter_subreg (&x); - /* X must not be a pseudo reg. */ - gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER); + /* If X is a pseudo-register, abort now rather than writing trash to the + assembler file. */ + + if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) + abort (); PRINT_OPERAND (asm_out_file, x, code); } @@ -3202,8 +3173,6 @@ output_addr_const (FILE *file, rtx x) break; case SYMBOL_REF: - if (SYMBOL_REF_DECL (x)) - mark_decl_referenced (SYMBOL_REF_DECL (x)); #ifdef ASM_OUTPUT_SYMBOL_REF ASM_OUTPUT_SYMBOL_REF (file, x); #else @@ -3468,7 +3437,7 @@ asm_fprintf (FILE *file, const char *p, ...) ASM_FPRINTF_EXTENSIONS (file, argptr, p) #endif default: - gcc_unreachable (); + abort (); } break; @@ -3615,8 +3584,8 @@ split_double (rtx value, rtx *first, rtx *second) } #endif - *first = GEN_INT (l[0]); - *second = GEN_INT (l[1]); + *first = GEN_INT ((HOST_WIDE_INT) l[0]); + *second = GEN_INT ((HOST_WIDE_INT) l[1]); } } @@ -3633,12 +3602,12 @@ leaf_function_p (void) for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { - if (CALL_P (insn) + if (GET_CODE (insn) == CALL_INSN && ! SIBLING_CALL_P (insn)) return 0; - if (NONJUMP_INSN_P (insn) + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE - && CALL_P (XVECEXP (PATTERN (insn), 0, 0)) + && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) return 0; } @@ -3648,12 +3617,12 @@ leaf_function_p (void) { insn = XEXP (link, 0); - if (CALL_P (insn) + if (GET_CODE (insn) == CALL_INSN && ! SIBLING_CALL_P (insn)) return 0; - if (NONJUMP_INSN_P (insn) + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE - && CALL_P (XVECEXP (PATTERN (insn), 0, 0)) + && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) return 0; } @@ -3669,12 +3638,13 @@ int final_forward_branch_p (rtx insn) { int insn_id, label_id; - - gcc_assert (uid_shuid); + if (!uid_shuid) + abort (); insn_id = INSN_SHUID (insn); label_id = INSN_SHUID (JUMP_LABEL (insn)); /* We've hit some insns that does not have id information available. */ - gcc_assert (insn_id && label_id); + if (!insn_id || !label_id) + abort (); return insn_id < label_id; } @@ -3705,7 +3675,7 @@ only_leaf_regs_used (void) if (current_function_uses_pic_offset_table && pic_offset_table_rtx != 0 - && REG_P (pic_offset_table_rtx) + && GET_CODE (pic_offset_table_rtx) == REG && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)]) return 0; @@ -3749,7 +3719,7 @@ leaf_renumber_regs_insn (rtx in_rtx) renumbered_regs would be 1 for an output-register; they */ - if (REG_P (in_rtx)) + if (GET_CODE (in_rtx) == REG) { int newreg; @@ -3766,7 +3736,8 @@ leaf_renumber_regs_insn (rtx in_rtx) return; } newreg = LEAF_REG_REMAP (newreg); - gcc_assert (newreg >= 0); + if (newreg < 0) + abort (); regs_ever_live[REGNO (in_rtx)] = 0; regs_ever_live[newreg] = 1; REGNO (in_rtx) = newreg; @@ -3809,7 +3780,7 @@ leaf_renumber_regs_insn (rtx in_rtx) break; default: - gcc_unreachable (); + abort (); } } #endif @@ -3845,7 +3816,7 @@ debug_flush_symbol_queue (void) for (i = 0; i < symbol_queue_index; ++i) { - /* If we pushed queued symbols then such symbols must be + /* If we pushed queued symbols then such symbols are must be output no matter what anyone else says. Specifically, we need to make sure dbxout_symbol() thinks the symbol was used and also we need to override TYPE_DECL_SUPPRESS_DEBUG @@ -3895,192 +3866,3 @@ debug_free_queue (void) symbol_queue_size = 0; } } - -/* Turn the RTL into assembly. */ -static unsigned int -rest_of_handle_final (void) -{ - rtx x; - const char *fnname; - - /* Get the function's name, as described by its RTL. This may be - different from the DECL_NAME name used in the source file. */ - - x = DECL_RTL (current_function_decl); - gcc_assert (MEM_P (x)); - x = XEXP (x, 0); - gcc_assert (GET_CODE (x) == SYMBOL_REF); - fnname = XSTR (x, 0); - - assemble_start_function (current_function_decl, fnname); - final_start_function (get_insns (), asm_out_file, optimize); - final (get_insns (), asm_out_file, optimize); - final_end_function (); - -#ifdef TARGET_UNWIND_INFO - /* ??? The IA-64 ".handlerdata" directive must be issued before - the ".endp" directive that closes the procedure descriptor. */ - output_function_exception_table (); -#endif - - assemble_end_function (current_function_decl, fnname); - -#ifndef TARGET_UNWIND_INFO - /* Otherwise, it feels unclean to switch sections in the middle. */ - output_function_exception_table (); -#endif - - user_defined_section_attribute = false; - - if (! quiet_flag) - fflush (asm_out_file); - - /* Release all memory allocated by flow. */ - free_basic_block_vars (); - - /* Write DBX symbols if requested. */ - - /* Note that for those inline functions where we don't initially - know for certain that we will be generating an out-of-line copy, - the first invocation of this routine (rest_of_compilation) will - skip over this code by doing a `goto exit_rest_of_compilation;'. - Later on, wrapup_global_declarations will (indirectly) call - rest_of_compilation again for those inline functions that need - to have out-of-line copies generated. During that call, we - *will* be routed past here. */ - - timevar_push (TV_SYMOUT); - (*debug_hooks->function_decl) (current_function_decl); - timevar_pop (TV_SYMOUT); - return 0; -} - -struct tree_opt_pass pass_final = -{ - NULL, /* name */ - NULL, /* gate */ - rest_of_handle_final, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_FINAL, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_ggc_collect, /* todo_flags_finish */ - 0 /* letter */ -}; - - -static unsigned int -rest_of_handle_shorten_branches (void) -{ - /* Shorten branches. */ - shorten_branches (get_insns ()); - return 0; -} - -struct tree_opt_pass pass_shorten_branches = -{ - "shorten", /* name */ - NULL, /* gate */ - rest_of_handle_shorten_branches, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_FINAL, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ -}; - - -static unsigned int -rest_of_clean_state (void) -{ - rtx insn, next; - - /* It is very important to decompose the RTL instruction chain here: - debug information keeps pointing into CODE_LABEL insns inside the function - body. If these remain pointing to the other insns, we end up preserving - whole RTL chain and attached detailed debug info in memory. */ - for (insn = get_insns (); insn; insn = next) - { - next = NEXT_INSN (insn); - NEXT_INSN (insn) = NULL; - PREV_INSN (insn) = NULL; - } - - /* In case the function was not output, - don't leave any temporary anonymous types - queued up for sdb output. */ -#ifdef SDB_DEBUGGING_INFO - if (write_symbols == SDB_DEBUG) - sdbout_types (NULL_TREE); -#endif - - reload_completed = 0; - epilogue_completed = 0; - flow2_completed = 0; - no_new_pseudos = 0; -#ifdef STACK_REGS - regstack_completed = 0; -#endif - - /* Clear out the insn_length contents now that they are no - longer valid. */ - init_insn_lengths (); - - /* Show no temporary slots allocated. */ - init_temp_slots (); - - free_basic_block_vars (); - free_bb_for_insn (); - - - if (targetm.binds_local_p (current_function_decl)) - { - int pref = cfun->preferred_stack_boundary; - if (cfun->stack_alignment_needed > cfun->preferred_stack_boundary) - pref = cfun->stack_alignment_needed; - cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary - = pref; - } - - /* Make sure volatile mem refs aren't considered valid operands for - arithmetic insns. We must call this here if this is a nested inline - function, since the above code leaves us in the init_recog state, - and the function context push/pop code does not save/restore volatile_ok. - - ??? Maybe it isn't necessary for expand_start_function to call this - anymore if we do it here? */ - - init_recog_no_volatile (); - - /* We're done with this function. Free up memory if we can. */ - free_after_parsing (cfun); - free_after_compilation (cfun); - return 0; -} - -struct tree_opt_pass pass_clean_state = -{ - NULL, /* name */ - NULL, /* gate */ - rest_of_clean_state, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_FINAL, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - PROP_rtl, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ - 0 /* letter */ -}; - diff --git a/contrib/gcc/flags.h b/contrib/gcc/flags.h index 226fb60..e947f2a 100644 --- a/contrib/gcc/flags.h +++ b/contrib/gcc/flags.h @@ -1,6 +1,6 @@ /* Compilation switch flag definitions for GCC. Copyright (C) 1987, 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, - 2003, 2004, 2005, 2006, 2007 + 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -17,19 +17,18 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #ifndef GCC_FLAGS_H #define GCC_FLAGS_H -#include "options.h" - enum debug_info_type { NO_DEBUG, /* Write no debug info. */ DBX_DEBUG, /* Write BSD .stabs for DBX (using dbxout.c). */ SDB_DEBUG, /* Write COFF for (old) SDB (using sdbout.c). */ + DWARF_DEBUG, /* Write Dwarf debug info (using dwarfout.c). */ DWARF2_DEBUG, /* Write Dwarf v2 debug info (using dwarf2out.c). */ XCOFF_DEBUG, /* Write IBM/Xcoff debug info (using dbxout.c). */ VMS_DEBUG, /* Write VMS debug info (using vmsdbgout.c). */ @@ -58,30 +57,8 @@ extern enum debug_info_level debug_info_level; debugging information. */ extern bool use_gnu_debug_info_extensions; -/* Enumerate visibility settings. This is deliberately ordered from most - to least visibility. */ -#ifndef SYMBOL_VISIBILITY_DEFINED -#define SYMBOL_VISIBILITY_DEFINED -enum symbol_visibility -{ - VISIBILITY_DEFAULT, - VISIBILITY_PROTECTED, - VISIBILITY_HIDDEN, - VISIBILITY_INTERNAL -}; -#endif - -/* The default visibility for all symbols (unless overridden). */ -extern enum symbol_visibility default_visibility; - -struct visibility_flags -{ - unsigned inpragma : 1; /* True when in #pragma GCC visibility. */ - unsigned inlines_hidden : 1; /* True when -finlineshidden in effect. */ -}; - -/* Global visibility options. */ -extern struct visibility_flags visibility_options; +/* Nonzero means emit debugging information only for symbols which are used. */ +extern int flag_debug_only_used_symbols; /* Nonzero means do optimizations. -opt. */ @@ -91,17 +68,90 @@ extern int optimize; extern int optimize_size; +/* Don't print functions as they are compiled and don't print + times taken by the various passes. -quiet. */ + +extern int quiet_flag; + +/* Print memory still in use at end of compilation (which may have little + to do with peak memory consumption). -fmem-report. */ + +extern int mem_report; + +/* Don't print warning messages. -w. */ + +extern bool inhibit_warnings; + +/* Don't suppress warnings from system headers. -Wsystem-headers. */ + +extern bool warn_system_headers; + /* Do print extra warnings (such as for uninitialized variables). -W/-Wextra. */ extern bool extra_warnings; +/* If -Werror. */ + +extern bool warnings_are_errors; + /* Nonzero to warn about unused variables, functions et.al. Use set_Wunused() to update the -Wunused-* flags that correspond to the -Wunused option. */ extern void set_Wunused (int setting); +extern bool warn_unused_function; +extern bool warn_unused_label; +extern bool warn_unused_parameter; +extern bool warn_unused_variable; +extern bool warn_unused_value; + +/* Nonzero to warn about code which is never reached. */ + +extern bool warn_notreached; + +/* Nonzero means warn if inline function is too large. */ + +extern bool warn_inline; + +/* Nonzero to warn about variables used before they are initialized. */ + +extern int warn_uninitialized; + +/* Nonzero means warn about all declarations which shadow others. */ + +extern bool warn_shadow; + +/* Warn if a switch on an enum, that does not have a default case, + fails to have a case for every enum value. */ + +extern bool warn_switch; + +/* Warn if a switch does not have a default case. */ + +extern bool warn_switch_default; + +/* Warn if a switch on an enum fails to have a case for every enum + value (regardless of the presence or otherwise of a default case). */ + +extern bool warn_switch_enum; + +/* Nonzero means warn about function definitions that default the return type + or that use a null return and have a return-type other than void. */ + +extern int warn_return_type; + +/* Warn about functions which might be candidates for attribute noreturn. */ + +extern bool warn_missing_noreturn; + +/* Nonzero means warn about pointer casts that increase the required + alignment of the target type (and might therefore lead to a crash + due to a misaligned access). */ + +extern bool warn_cast_align; + /* Nonzero means warn about any objects definitions whose size is larger than N bytes. Also want about function definitions whose returned values are larger than N bytes. The value N is in `larger_than_size'. */ @@ -109,15 +159,69 @@ extern void set_Wunused (int setting); extern bool warn_larger_than; extern HOST_WIDE_INT larger_than_size; +/* Warn if a function returns an aggregate, + since there are often incompatible calling conventions for doing this. */ + +extern bool warn_aggregate_return; + +/* Warn if packed attribute on struct is unnecessary and inefficient. */ + +extern bool warn_packed; + +/* Warn when gcc pads a structure to an alignment boundary. */ + +extern bool warn_padded; + +/* Warn when an optimization pass is disabled. */ + +extern bool warn_disabled_optimization; + +/* Nonzero means warn about uses of __attribute__((deprecated)) + declarations. */ + +extern bool warn_deprecated_decl; + /* Nonzero means warn about constructs which might not be strict aliasing safe. */ -extern int warn_strict_aliasing; +extern bool warn_strict_aliasing; + +/* Nonzero if generating code to do profiling. */ + +extern int profile_flag; + +/* Nonzero if generating code to profile program flow graph arcs. */ + +extern int profile_arc_flag; -/* Nonzero means warn about optimizations which rely on undefined - signed overflow. */ +/* Nonzero if value profile should be measured. */ -extern int warn_strict_overflow; +extern int flag_profile_values; + +/* Nonzero if generating info for gcov to calculate line test coverage. */ + +extern int flag_test_coverage; + +/* Nonzero indicates that branch taken probabilities should be calculated. */ + +extern int flag_branch_probabilities; + +/* Nonzero if basic blocks should be reordered. */ + +extern int flag_reorder_blocks; + +/* Nonzero if functions should be reordered. */ + +extern int flag_reorder_functions; + +/* Nonzero if registers should be renamed. */ + +extern int flag_rename_registers; + +/* Nonzero for -pedantic switch: warn about anything + that standard C forbids. */ + +extern int pedantic; /* Temporarily suppress certain warnings. This is set while reading code from a system header file. */ @@ -135,20 +239,163 @@ extern int flag_print_asm_name; extern int flag_signed_char; -/* Nonzero means give an enum type only as many bytes as it needs. A value - of 2 means it has not yet been initialized. */ +/* Nonzero means give an enum type only as many bytes as it needs. */ extern int flag_short_enums; +/* Nonzero for -fcaller-saves: allocate values in regs that need to + be saved across function calls, if that produces overall better code. + Optional now, so people can test it. */ + +extern int flag_caller_saves; + /* Nonzero for -fpcc-struct-return: return values the same way PCC does. */ extern int flag_pcc_struct_return; +/* Nonzero for -fforce-mem: load memory value into a register + before arithmetic on it. This makes better cse but slower compilation. */ + +extern int flag_force_mem; + +/* Nonzero for -fforce-addr: load memory address into a register before + reference to memory. This makes better cse but slower compilation. */ + +extern int flag_force_addr; + +/* Nonzero for -fdefer-pop: don't pop args after each function call; + instead save them up to pop many calls' args with one insns. */ + +extern int flag_defer_pop; + +/* Nonzero for -ffloat-store: don't allocate floats and doubles + in extended-precision registers. */ + +extern int flag_float_store; + +/* Nonzero enables strength-reduction in loop.c. */ + +extern int flag_strength_reduce; + +/* Nonzero enables loop unrolling in unroll.c. Only loops for which the + number of iterations can be calculated at compile-time (UNROLL_COMPLETELY, + UNROLL_MODULO) or at run-time (preconditioned to be UNROLL_MODULO) are + unrolled. */ + +extern int flag_old_unroll_loops; + +/* Nonzero enables loop unrolling in unroll.c. All loops are unrolled. + This is generally not a win. */ + +extern int flag_old_unroll_all_loops; + +/* Nonzero forces all invariant computations in loops to be moved + outside the loop. */ + +extern int flag_move_all_movables; + +/* Nonzero enables prefetch optimizations for arrays in loops. */ + +extern int flag_prefetch_loop_arrays; + +/* Nonzero forces all general induction variables in loops to be + strength reduced. */ + +extern int flag_reduce_all_givs; + +/* Nonzero for -fcse-follow-jumps: + have cse follow jumps to do a more extensive job. */ + +extern int flag_cse_follow_jumps; + +/* Nonzero for -fcse-skip-blocks: + have cse follow a branch around a block. */ + +extern int flag_cse_skip_blocks; + +/* Nonzero for -fexpensive-optimizations: + perform miscellaneous relatively-expensive optimizations. */ +extern int flag_expensive_optimizations; + +/* Nonzero for -fwritable-strings: + store string constants in data segment and don't uniquize them. */ + +extern int flag_writable_strings; + +/* Nonzero means don't put addresses of constant functions in registers. + Used for compiling the Unix kernel, where strange substitutions are + done on the assembly output. */ + +extern int flag_no_function_cse; + +/* Nonzero for -fomit-frame-pointer: + don't make a frame pointer in simple functions that don't require one. */ + +extern int flag_omit_frame_pointer; + +/* Nonzero to inhibit use of define_optimization peephole opts. */ + +extern int flag_no_peephole; + +/* Nonzero allows GCC to optimize sibling and tail recursive calls. */ + +extern int flag_optimize_sibling_calls; + +/* Nonzero means the front end generally wants `errno' maintained by math + operations, like built-in SQRT. */ + +extern int flag_errno_math; + +/* Nonzero means that unsafe floating-point math optimizations are allowed + for the sake of speed. IEEE compliance is not guaranteed, and operations + are allowed to assume that their arguments and results are "normal" + (e.g., nonnegative for SQRT). */ + +extern int flag_unsafe_math_optimizations; + +/* Nonzero means that no NaNs or +-Infs are expected. */ + +extern int flag_finite_math_only; + +/* Zero means that floating-point math operations cannot generate a + (user-visible) trap. This is the case, for example, in nonstop + IEEE 754 arithmetic. */ + +extern int flag_trapping_math; + +/* Nonzero means disable transformations that assume default floating + point rounding behavior. */ + +extern int flag_rounding_math; + /* 0 means straightforward implementation of complex divide acceptable. 1 means wide ranges of inputs must work for complex divide. - 2 means C99-like requirements for complex multiply and divide. */ + 2 means C99-like requirements for complex divide (not yet implemented). */ + +extern int flag_complex_divide_method; + +/* Nonzero means to run loop optimizations twice. */ + +extern int flag_rerun_loop_opt; + +/* Nonzero means make functions that look like good inline candidates + go inline. */ + +extern int flag_inline_functions; + +/* Nonzero for -fkeep-inline-functions: even if we make a function + go inline everywhere, keep its definition around for debugging + purposes. */ -extern int flag_complex_method; +extern int flag_keep_inline_functions; + +/* Nonzero means that functions declared `inline' will be treated + as `static'. Prevents generation of zillions of copies of unused + static inline functions; instead, `inlines' are written out + only when actually used. Used in conjunction with -g. Also + does the right thing with #pragma interface. */ + +extern int flag_no_inline; /* Nonzero means that we don't want inlining by virtue of -fno-inline, not just because the tree inliner turned us off. */ @@ -157,12 +404,69 @@ extern int flag_really_no_inline; /* Nonzero if we are only using compiler to check syntax errors. */ -extern int rtl_dump_and_exit; +extern int flag_syntax_only; /* Nonzero means we should save auxiliary info into a .X file. */ extern int flag_gen_aux_info; +/* Nonzero means make the text shared if supported. */ + +extern int flag_shared_data; + +/* flag_schedule_insns means schedule insns within basic blocks (before + local_alloc). + flag_schedule_insns_after_reload means schedule insns after + global_alloc. */ + +extern int flag_schedule_insns; +extern int flag_schedule_insns_after_reload; +extern int flag_sched2_use_superblocks; +extern int flag_sched2_use_traces; + +/* The following flags have effect only for scheduling before register + allocation: + + flag_schedule_interblock means schedule insns across basic blocks. + flag_schedule_speculative means allow speculative motion of non-load insns. + flag_schedule_speculative_load means allow speculative motion of some + load insns. + flag_schedule_speculative_load_dangerous allows speculative motion of more + load insns. */ + +extern int flag_schedule_interblock; +extern int flag_schedule_speculative; +extern int flag_schedule_speculative_load; +extern int flag_schedule_speculative_load_dangerous; + +/* The following flags have an effect during scheduling after register + allocation: + + sched_stalled_insns means that insns can be moved prematurely from the queue + of stalled insns into the ready list. + + sched_stalled_insns_dep controls how many recently scheduled cycles will + be examined for a dependency on a stalled insn that is candidate for + premature removal from the queue of stalled insns into the ready list (has + an effect only if the flag 'sched_stalled_insns' is set). */ + +extern int flag_sched_stalled_insns; +extern int flag_sched_stalled_insns_dep; + +/* flag_branch_on_count_reg means try to replace add-1,compare,branch tupple + by a cheaper branch, on a count register. */ +extern int flag_branch_on_count_reg; + +/* This option is set to 1 on -fsingle-precision-constant option which is + used to convert the floating point constants to single precision + constants. */ + +extern int flag_single_precision_constant; + +/* Nonzero means put things in delayed-branch slots if supported. */ + +extern int flag_delayed_branch; + /* Nonzero means suppress output of instruction numbers and line number notes in debugging dumps. */ @@ -173,11 +477,63 @@ extern int flag_dump_unnumbered; extern int flag_pedantic_errors; +/* Nonzero means generate position-independent code. 1 vs 2 for a + target-dependent "small" or "large" mode. */ + +extern int flag_pic; + +/* Nonzero if we are compiling position independent code for executable. + 1 vs 2 for a target-dependent "small" or "large" mode. */ + +extern int flag_pie; + /* Nonzero if we are compiling code for a shared library, zero for executable. */ extern int flag_shlib; +/* Nonzero means generate extra code for exception handling and enable + exception handling. */ + +extern int flag_exceptions; + +/* Nonzero means generate frame unwind info table when supported. */ + +extern int flag_unwind_tables; + +/* Nonzero means generate frame unwind info table exact at each insn boundary. */ + +extern int flag_asynchronous_unwind_tables; + +/* Nonzero means don't place uninitialized global data in common storage + by default. */ + +extern int flag_no_common; + +/* -finhibit-size-directive inhibits output of .size for ELF. + This is used only for compiling crtstuff.c, + and it may be extended to other effects + needed for crtstuff.c on other systems. */ +extern int flag_inhibit_size_directive; + +/* Nonzero means place each function into its own section on those platforms + which support arbitrary section names and unlimited numbers of sections. */ + +extern int flag_function_sections; + +/* ... and similar for data. */ + +extern int flag_data_sections; + +/* -fverbose-asm causes extra commentary information to be produced in + the generated assembly code (to make it more readable). This option + is generally only of use to those who actually need to read the + generated assembly code (perhaps while debugging the compiler itself). + -fno-verbose-asm, the default, causes the extra information + to not be added and is useful when comparing two assembler files. */ + +extern int flag_verbose_asm; + /* -dA causes debug information to be produced in the generated assembly code (to make it more readable). This option is generally only of use to those who actually need to read the @@ -187,11 +543,56 @@ extern int flag_shlib; extern int flag_debug_asm; -/* Generate code for GNU or NeXT Objective-C runtime environment. */ +extern int flag_dump_rtl_in_asm; -extern int flag_next_runtime; +/* Greater than zero if user symbols are prepended by a leading underscore + in generated assembly code. */ +extern int flag_leading_underscore; -extern int flag_dump_rtl_in_asm; +/* Tag all structures with __attribute__(packed) */ +extern int flag_pack_struct; + +/* This flag is only tested if alias checking is enabled. + 0 if pointer arguments may alias each other. True in C. + 1 if pointer arguments may not alias each other but may alias + global variables. + 2 if pointer arguments may not alias each other and may not + alias global variables. True in Fortran. + The value is ignored if flag_alias_check is 0. */ +extern int flag_argument_noalias; + +/* Nonzero if we should do (language-dependent) alias analysis. + Typically, this analysis will assume that expressions of certain + types do not alias expressions of certain other types. Only used + if alias analysis (in general) is enabled. */ +extern int flag_strict_aliasing; + +/* Emit code to probe the stack, to help detect stack overflow; also + may cause large objects to be allocated dynamically. */ +extern int flag_stack_check; + +/* Do the full regmove optimization pass. */ +extern int flag_regmove; + +/* Instrument functions with calls at entry and exit, for profiling. */ +extern int flag_instrument_function_entry_exit; + +/* Perform a peephole pass before sched2. */ +extern int flag_peephole2; + +/* Try to guess branch probabilities. */ +extern int flag_guess_branch_prob; + +/* -fcheck-bounds causes gcc to generate array bounds checks. + For C, C++ and ObjC: defaults off. + For Java: defaults to on. + For Fortran: defaults to off. */ +extern int flag_bounds_check; + +/* This will attempt to merge constant section constants, if 1 only + string constants and constants from constant pool, if 2 also constant + variables. */ +extern int flag_merge_constants; /* If one, renumber instruction UIDs to reduce the number of unused UIDs if there are a lot of instructions. If greater than @@ -206,6 +607,13 @@ extern int flag_renumber_insns; extern int frame_pointer_needed; +/* Nonzero if the generated code should trap on signed overflow + for PLUS / SUB / MULT. */ +extern int flag_trapv; + +/* Nonzero if the signed arithmetic overflow should wrap around. */ +extern int flag_wrapv; + /* Nonzero if subexpressions must be evaluated from left-to-right. */ extern int flag_evaluation_order; @@ -218,12 +626,16 @@ extern bool g_switch_set; For each variable, there is an _log variant which is the power of two not less than the variable, for .align output. */ +extern int align_loops; extern int align_loops_log; extern int align_loops_max_skip; +extern int align_jumps; extern int align_jumps_log; extern int align_jumps_max_skip; +extern int align_labels; extern int align_labels_log; extern int align_labels_max_skip; +extern int align_functions; extern int align_functions_log; /* Like align_functions_log above, but used by front-ends to force the @@ -241,26 +653,92 @@ enum graph_dump_types }; extern enum graph_dump_types graph_dump_format; +/* Nonzero means ignore `#ident' directives. 0 means handle them. + On SVR4 targets, it also controls whether or not to emit a + string identifying the compiler. */ + +extern int flag_no_ident; + +/* Nonzero means perform global CSE. */ + +extern int flag_gcse; + +/* Nonzero if we want to perform enhanced load motion during gcse. */ + +extern int flag_gcse_lm; + +/* Nonzero if we want to perform store motion after gcse. */ + +extern int flag_gcse_sm; + +/* Nonzero if we want to perform redundant load-after-store elimination + in gcse. */ + +extern int flag_gcse_las; + +/* Nonzero if value histograms should be used to optimize code. */ +extern int flag_value_profile_transformations; + +/* Perform branch target register optimization before prologue / epilogue + threading. */ + +extern int flag_branch_target_load_optimize; + +/* Perform branch target register optimization after prologue / epilogue + threading and jump2. */ + +extern int flag_branch_target_load_optimize2; + + +/* Nonzero means we should do dwarf2 duplicate elimination. */ + +extern int flag_eliminate_dwarf2_dups; + +/* Nonzero means we should do unused type elimination. */ + +extern int flag_eliminate_unused_debug_types; + /* Nonzero means to collect statistics which might be expensive and to print them when we are done. */ extern int flag_detailed_statistics; +/* Nonzero means enable synchronous exceptions for non-call instructions. */ +extern int flag_non_call_exceptions; + +/* Nonzero means put zero initialized data in the bss section. */ +extern int flag_zero_initialized_in_bss; + +/* Nonzero means disable transformations observable by signaling NaNs. */ +extern int flag_signaling_nans; + +extern int flag_unit_at_a_time; + +extern int flag_web; + /* Nonzero means that we defer emitting functions until they are actually used. */ extern int flag_remove_unreachable_functions; -/* Nonzero if we should track variables. */ -extern int flag_var_tracking; - -/* True if flag_speculative_prefetching was set by user. Used to suppress - warning message in case flag was set by -fprofile-{generate,use}. */ -extern bool flag_speculative_prefetching_set; - /* A string that's used when a random name is required. NULL means to make it really random. */ extern const char *flag_random_seed; +/* The version of the C++ ABI in use. The following values are + allowed: + + 0: The version of the ABI believed most conformant with the + C++ ABI specification. This ABI may change as bugs are + discovered and fixed. Therefore, 0 will not necessarily + indicate the same ABI in different versions of G++. + + 1: The version of the ABI first used in G++ 3.2. + + Additional positive integers will be assigned as new versions of + the ABI become the default version of the ABI. */ + +extern int flag_abi_version; + /* Returns TRUE if generated code should match ABI version N or greater is in use. */ @@ -269,7 +747,7 @@ extern const char *flag_random_seed; /* True if the given mode has a NaN representation and the treatment of NaN operands is important. Certain optimizations, such as folding - x * 0 into 0, are not correct for NaN operands, and are normally + x * 0 into x, are not correct for NaN operands, and are normally disabled for modes with NaNs. The user can ask for them to be done anyway using the -funsafe-math-optimizations switch. */ #define HONOR_NANS(MODE) \ @@ -293,53 +771,4 @@ extern const char *flag_random_seed; #define HONOR_SIGN_DEPENDENT_ROUNDING(MODE) \ (MODE_HAS_SIGN_DEPENDENT_ROUNDING (MODE) && flag_rounding_math) -/* True if overflow wraps around for the given integral type. That - is, TYPE_MAX + 1 == TYPE_MIN. */ -#define TYPE_OVERFLOW_WRAPS(TYPE) \ - (TYPE_UNSIGNED (TYPE) || flag_wrapv) - -/* True if overflow is undefined for the given integral type. We may - optimize on the assumption that values in the type never overflow. - - IMPORTANT NOTE: Any optimization based on TYPE_OVERFLOW_UNDEFINED - must issue a warning based on warn_strict_overflow. In some cases - it will be appropriate to issue the warning immediately, and in - other cases it will be appropriate to simply set a flag and let the - caller decide whether a warning is appropriate or not. */ -#define TYPE_OVERFLOW_UNDEFINED(TYPE) \ - (!TYPE_UNSIGNED (TYPE) && !flag_wrapv && !flag_trapv && flag_strict_overflow) - -/* True if overflow for the given integral type should issue a - trap. */ -#define TYPE_OVERFLOW_TRAPS(TYPE) \ - (!TYPE_UNSIGNED (TYPE) && flag_trapv) - -/* Names for the different levels of -Wstrict-overflow=N. The numeric - values here correspond to N. */ - -enum warn_strict_overflow_code -{ - /* Overflow warning that should be issued with -Wall: a questionable - construct that is easy to avoid even when using macros. Example: - folding (x + CONSTANT > x) to 1. */ - WARN_STRICT_OVERFLOW_ALL = 1, - /* Overflow warning about folding a comparison to a constant because - of undefined signed overflow, other than cases covered by - WARN_STRICT_OVERFLOW_ALL. Example: folding (abs (x) >= 0) to 1 - (this is false when x == INT_MIN). */ - WARN_STRICT_OVERFLOW_CONDITIONAL = 2, - /* Overflow warning about changes to comparisons other than folding - them to a constant. Example: folding (x + 1 > 1) to (x > 0). */ - WARN_STRICT_OVERFLOW_COMPARISON = 3, - /* Overflow warnings not covered by the above cases. Example: - folding ((x * 10) / 5) to (x * 2). */ - WARN_STRICT_OVERFLOW_MISC = 4, - /* Overflow warnings about reducing magnitude of constants in - comparison. Example: folding (x + 2 > y) to (x + 1 >= y). */ - WARN_STRICT_OVERFLOW_MAGNITUDE = 5 -}; - -/* Whether to emit an overflow warning whose code is C. */ -#define issue_strict_overflow_warning(c) (warn_strict_overflow >= (int) (c)) - #endif /* ! GCC_FLAGS_H */ diff --git a/contrib/gcc/function.c b/contrib/gcc/function.c index 5e43484..8679729 100644 --- a/contrib/gcc/function.c +++ b/contrib/gcc/function.c @@ -1,7 +1,6 @@ /* Expands front end tree to back end RTL for GCC. Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -17,8 +16,10 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* $FreeBSD$ */ /* This file handles the generation of rtl code from tree structure at the level of the function as a whole. @@ -32,7 +33,12 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA Call `assign_stack_local' to allocate a stack slot for a local variable. This is usually done during the RTL generation for the function body, but it can also be done in the reload pass when a pseudo-register does - not get a hard register. */ + not get a hard register. + + Call `put_var_into_stack' when you learn, belatedly, that a variable + previously given a pseudo-register must in fact go in the stack. + This function changes the DECL_RTL to be a stack slot instead of a reg + then scans all the RTL instructions so far generated to correct them. */ #include "config.h" #include "system.h" @@ -59,11 +65,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "integrate.h" #include "langhooks.h" #include "target.h" -#include "cfglayout.h" -#include "tree-gimple.h" -#include "tree-pass.h" -#include "predict.h" -#include "vecprim.h" + +#ifndef TRAMPOLINE_ALIGNMENT +#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY +#endif #ifndef LOCAL_ALIGNMENT #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT @@ -92,12 +97,27 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA alignment. */ #define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1)) +/* NEED_SEPARATE_AP means that we cannot derive ap from the value of fp + during rtl generation. If they are different register numbers, this is + always true. It may also be true if + FIRST_PARM_OFFSET - STARTING_FRAME_OFFSET is not a constant during rtl + generation. See fix_lexical_addr for details. */ + +#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM +#define NEED_SEPARATE_AP +#endif + /* Nonzero if function being compiled doesn't contain any calls (ignoring the prologue and epilogue). This is set prior to local register allocation and is valid for the remaining compiler passes. */ int current_function_is_leaf; +/* Nonzero if function being compiled doesn't contain any instructions + that can throw an exception. This is set prior to final. */ + +int current_function_nothrow; + /* Nonzero if function being compiled doesn't modify the stack pointer (ignoring the prologue and epilogue). This is only valid after life_analysis has run. */ @@ -114,6 +134,9 @@ int current_function_uses_only_leaf_regs; post-instantiation libcalls. */ int virtuals_instantiated; +/* Nonzero if at least one trampoline has been created. */ +int trampolines_created; + /* Assign unique numbers to labels generated for profiling, debugging, etc. */ static GTY(()) int funcdef_no; @@ -121,16 +144,19 @@ static GTY(()) int funcdef_no; target specific, per-function data structures. */ struct machine_function * (*init_machine_status) (void); +/* The FUNCTION_DECL for an inline function currently being expanded. */ +tree inline_function_decl; + /* The currently compiled function. */ struct function *cfun = 0; /* These arrays record the INSN_UIDs of the prologue and epilogue insns. */ -static VEC(int,heap) *prologue; -static VEC(int,heap) *epilogue; +static GTY(()) varray_type prologue; +static GTY(()) varray_type epilogue; /* Array of INSN_UIDs to hold the INSN_UIDs for each sibcall epilogue in this function. */ -static VEC(int,heap) *sibcall_epilogue; +static GTY(()) varray_type sibcall_epilogue; /* In order to evaluate some expressions, such as function calls returning structures in memory, we need to temporarily allocate stack locations. @@ -154,9 +180,6 @@ struct temp_slot GTY(()) { /* Points to next temporary slot. */ struct temp_slot *next; - /* Points to previous temporary slot. */ - struct temp_slot *prev; - /* The rtx to used to reference the slot. */ rtx slot; /* The rtx used to represent the address if not the address of the @@ -171,6 +194,8 @@ struct temp_slot GTY(()) It can be reused if objects of the type of the new slot will always conflict with objects of the type of the old slot. */ tree type; + /* The value of `sequence_rtl_expr' when this temporary is allocated. */ + tree rtl_expr; /* Nonzero if this temporary is currently in use. */ char in_use; /* Nonzero if this temporary has its address taken. */ @@ -187,35 +212,96 @@ struct temp_slot GTY(()) HOST_WIDE_INT full_size; }; +/* This structure is used to record MEMs or pseudos used to replace VAR, any + SUBREGs of VAR, and any MEMs containing VAR as an address. We need to + maintain this list in case two operands of an insn were required to match; + in that case we must ensure we use the same replacement. */ + +struct fixup_replacement GTY(()) +{ + rtx old; + rtx new; + struct fixup_replacement *next; +}; + +struct insns_for_mem_entry +{ + /* A MEM. */ + rtx key; + /* These are the INSNs which reference the MEM. */ + rtx insns; +}; + /* Forward declarations. */ static rtx assign_stack_local_1 (enum machine_mode, HOST_WIDE_INT, int, struct function *); static struct temp_slot *find_temp_slot_from_address (rtx); +static void put_reg_into_stack (struct function *, rtx, tree, enum machine_mode, + unsigned int, bool, bool, bool, htab_t); +static void schedule_fixup_var_refs (struct function *, rtx, tree, enum machine_mode, + htab_t); +static void fixup_var_refs (rtx, enum machine_mode, int, rtx, htab_t); +static struct fixup_replacement + *find_fixup_replacement (struct fixup_replacement **, rtx); +static void fixup_var_refs_insns (rtx, rtx, enum machine_mode, int, int, rtx); +static void fixup_var_refs_insns_with_hash (htab_t, rtx, enum machine_mode, int, rtx); +static void fixup_var_refs_insn (rtx, rtx, enum machine_mode, int, int, rtx); +static void fixup_var_refs_1 (rtx, enum machine_mode, rtx *, rtx, + struct fixup_replacement **, rtx); +static rtx fixup_memory_subreg (rtx, rtx, enum machine_mode, int); +static rtx walk_fixup_memory_subreg (rtx, rtx, enum machine_mode, int); +static rtx fixup_stack_1 (rtx, rtx); +static void optimize_bit_field (rtx, rtx, rtx *); +static void instantiate_decls (tree, int); +static void instantiate_decls_1 (tree, int); +static void instantiate_decl (rtx, HOST_WIDE_INT, int); +static rtx instantiate_new_reg (rtx, HOST_WIDE_INT *); +static int instantiate_virtual_regs_1 (rtx *, rtx, int); +static void delete_handlers (void); static void pad_to_arg_alignment (struct args_size *, int, struct args_size *); static void pad_below (struct args_size *, enum machine_mode, tree); -static void reorder_blocks_1 (rtx, tree, VEC(tree,heap) **); +static rtx round_trampoline_addr (rtx); +static rtx adjust_trampoline_addr (rtx); +static tree *identify_blocks_1 (rtx, tree *, tree *, tree *); +static void reorder_blocks_0 (tree); +static void reorder_blocks_1 (rtx, tree, varray_type *); +static void reorder_fix_fragments (tree); +static tree blocks_nreverse (tree); static int all_blocks (tree, tree *); static tree *get_block_vector (tree, int *); extern tree debug_find_var_in_block_tree (tree, tree); -/* We always define `record_insns' even if it's not used so that we +/* We always define `record_insns' even if its not used so that we can always export `prologue_epilogue_contains'. */ -static void record_insns (rtx, VEC(int,heap) **) ATTRIBUTE_UNUSED; -static int contains (rtx, VEC(int,heap) **); +static void record_insns (rtx, varray_type *) ATTRIBUTE_UNUSED; +static int contains (rtx, varray_type); #ifdef HAVE_return static void emit_return_into_block (basic_block, rtx); #endif +static void put_addressof_into_stack (rtx, htab_t); +static bool purge_addressof_1 (rtx *, rtx, int, int, int, htab_t); +static void purge_single_hard_subreg_set (rtx); #if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX) static rtx keep_stack_depressed (rtx); #endif +static int is_addressof (rtx *, void *); +static hashval_t insns_for_mem_hash (const void *); +static int insns_for_mem_comp (const void *, const void *); +static int insns_for_mem_walk (rtx *, void *); +static void compute_insns_for_mem (rtx, rtx, htab_t); static void prepare_function_start (tree); static void do_clobber_return_reg (rtx, void *); static void do_use_return_reg (rtx, void *); +static void instantiate_virtual_regs_lossage (rtx); +static tree split_complex_args (tree); static void set_insn_locators (rtx, int) ATTRIBUTE_UNUSED; /* Pointer to chain of `struct function' for containing functions. */ struct function *outer_function_chain; +/* List of insns that were postponed by purge_addressof_1. */ +static rtx postponed_insns; + /* Given a function decl for a containing function, return the `struct function' for it. */ @@ -228,7 +314,7 @@ find_function_data (tree decl) if (p->decl == decl) return p; - gcc_unreachable (); + abort (); } /* Save the current context for compilation of a nested function. @@ -238,18 +324,30 @@ find_function_data (tree decl) variables. */ void -push_function_context_to (tree context ATTRIBUTE_UNUSED) +push_function_context_to (tree context) { struct function *p; + if (context) + { + if (context == current_function_decl) + cfun->contains_functions = 1; + else + { + struct function *containing = find_function_data (context); + containing->contains_functions = 1; + } + } + if (cfun == 0) init_dummy_function_start (); p = cfun; p->outer = outer_function_chain; outer_function_chain = p; + p->fixup_var_refs_queue = 0; - lang_hooks.function.enter_nested (p); + (*lang_hooks.function.enter_nested) (p); cfun = 0; } @@ -267,15 +365,46 @@ void pop_function_context_from (tree context ATTRIBUTE_UNUSED) { struct function *p = outer_function_chain; + struct var_refs_queue *queue; cfun = p; outer_function_chain = p->outer; current_function_decl = p->decl; + reg_renumber = 0; + + restore_emit_status (p); - lang_hooks.function.leave_nested (p); + (*lang_hooks.function.leave_nested) (p); + + /* Finish doing put_var_into_stack for any of our variables which became + addressable during the nested function. If only one entry has to be + fixed up, just do that one. Otherwise, first make a list of MEMs that + are not to be unshared. */ + if (p->fixup_var_refs_queue == 0) + ; + else if (p->fixup_var_refs_queue->next == 0) + fixup_var_refs (p->fixup_var_refs_queue->modified, + p->fixup_var_refs_queue->promoted_mode, + p->fixup_var_refs_queue->unsignedp, + p->fixup_var_refs_queue->modified, 0); + else + { + rtx list = 0; + + for (queue = p->fixup_var_refs_queue; queue; queue = queue->next) + list = gen_rtx_EXPR_LIST (VOIDmode, queue->modified, list); + + for (queue = p->fixup_var_refs_queue; queue; queue = queue->next) + fixup_var_refs (queue->modified, queue->promoted_mode, + queue->unsignedp, list, 0); + + } + + p->fixup_var_refs_queue = 0; /* Reset variables that have known state during rtx generation. */ + rtx_equal_function_value_matters = 1; virtuals_instantiated = 0; generating_concat_p = 1; } @@ -298,7 +427,8 @@ free_after_parsing (struct function *f) /* f->varasm is used by code generation. */ /* f->eh->eh_return_stub_label is used by code generation. */ - lang_hooks.function.final (f); + (*lang_hooks.function.final) (f); + f->stmt = NULL; } /* Clear out all parts of the state in F that can safely be discarded @@ -308,29 +438,41 @@ free_after_parsing (struct function *f) void free_after_compilation (struct function *f) { - VEC_free (int, heap, prologue); - VEC_free (int, heap, epilogue); - VEC_free (int, heap, sibcall_epilogue); - f->eh = NULL; f->expr = NULL; f->emit = NULL; f->varasm = NULL; f->machine = NULL; - f->cfg = NULL; - f->x_avail_temp_slots = NULL; - f->x_used_temp_slots = NULL; + f->x_temp_slots = NULL; f->arg_offset_rtx = NULL; f->return_rtx = NULL; f->internal_arg_pointer = NULL; + f->x_nonlocal_labels = NULL; + f->x_nonlocal_goto_handler_slots = NULL; f->x_nonlocal_goto_handler_labels = NULL; + f->x_nonlocal_goto_stack_level = NULL; + f->x_cleanup_label = NULL; f->x_return_label = NULL; f->x_naked_return_label = NULL; + f->computed_goto_common_label = NULL; + f->computed_goto_common_reg = NULL; + f->x_save_expr_regs = NULL; f->x_stack_slot_list = NULL; - f->x_stack_check_probe_note = NULL; + f->x_rtl_expr_chain = NULL; + f->x_tail_recursion_label = NULL; + f->x_tail_recursion_reentry = NULL; f->x_arg_pointer_save_area = NULL; + f->x_clobber_return_insn = NULL; + f->x_context_display = NULL; + f->x_trampoline_list = NULL; f->x_parm_birth_insn = NULL; + f->x_last_parm_insn = NULL; + f->x_parm_reg_stack_loc = NULL; + f->fixup_var_refs_queue = NULL; + f->original_arg_vector = NULL; + f->original_decl_initial = NULL; + f->inl_last_parm_insn = NULL; f->epilogue_delay_list = NULL; } @@ -341,45 +483,25 @@ free_after_compilation (struct function *f) This size counts from zero. It is not rounded to PREFERRED_STACK_BOUNDARY; the caller may have to do that. */ -static HOST_WIDE_INT +HOST_WIDE_INT get_func_frame_size (struct function *f) { - if (FRAME_GROWS_DOWNWARD) - return -f->x_frame_offset; - else - return f->x_frame_offset; +#ifdef FRAME_GROWS_DOWNWARD + return -f->x_frame_offset; +#else + return f->x_frame_offset; +#endif } /* Return size needed for stack frame based on slots so far allocated. This size counts from zero. It is not rounded to PREFERRED_STACK_BOUNDARY; the caller may have to do that. */ - HOST_WIDE_INT get_frame_size (void) { return get_func_frame_size (cfun); } -/* Issue an error message and return TRUE if frame OFFSET overflows in - the signed target pointer arithmetics for function FUNC. Otherwise - return FALSE. */ - -bool -frame_offset_overflow (HOST_WIDE_INT offset, tree func) -{ - unsigned HOST_WIDE_INT size = FRAME_GROWS_DOWNWARD ? -offset : offset; - - if (size > ((unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (Pmode) - 1)) - /* Leave room for the fixed part of the frame. */ - - 64 * UNITS_PER_WORD) - { - error ("%Jtotal size of local objects too large", func); - return TRUE; - } - - return FALSE; -} - /* Allocate a stack slot of SIZE bytes and return a MEM rtx for it with machine mode MODE. @@ -399,7 +521,7 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align, { rtx x, addr; int bigend_correction = 0; - unsigned int alignment; + int alignment; int frame_off, frame_alignment, frame_phase; if (align == 0) @@ -413,7 +535,7 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align, /* Allow the target to (possibly) increase the alignment of this stack slot. */ - type = lang_hooks.types.type_for_mode (mode, 0); + type = (*lang_hooks.types.type_for_mode) (mode, 0); if (type) alignment = LOCAL_ALIGNMENT (type, alignment); @@ -429,8 +551,9 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align, else alignment = align / BITS_PER_UNIT; - if (FRAME_GROWS_DOWNWARD) - function->x_frame_offset -= size; +#ifdef FRAME_GROWS_DOWNWARD + function->x_frame_offset -= size; +#endif /* Ignore alignment we can't do with expected alignment of the boundary. */ if (alignment * BITS_PER_UNIT > PREFERRED_STACK_BOUNDARY) @@ -456,21 +579,20 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align, division with a negative dividend isn't as well defined as we might like. So we instead assume that ALIGNMENT is a power of two and use logical operations which are unambiguous. */ - if (FRAME_GROWS_DOWNWARD) - function->x_frame_offset - = (FLOOR_ROUND (function->x_frame_offset - frame_phase, - (unsigned HOST_WIDE_INT) alignment) - + frame_phase); - else - function->x_frame_offset - = (CEIL_ROUND (function->x_frame_offset - frame_phase, - (unsigned HOST_WIDE_INT) alignment) - + frame_phase); +#ifdef FRAME_GROWS_DOWNWARD + function->x_frame_offset + = (FLOOR_ROUND (function->x_frame_offset - frame_phase, alignment) + + frame_phase); +#else + function->x_frame_offset + = (CEIL_ROUND (function->x_frame_offset - frame_phase, alignment) + + frame_phase); +#endif } /* On a big-endian machine, if we are allocating more space than we will use, use the least significant bytes of those that are allocated. */ - if (BYTES_BIG_ENDIAN && mode != BLKmode && GET_MODE_SIZE (mode) < size) + if (BYTES_BIG_ENDIAN && mode != BLKmode) bigend_correction = size - GET_MODE_SIZE (mode); /* If we have already instantiated virtual registers, return the actual @@ -486,18 +608,15 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align, (function->x_frame_offset + bigend_correction, Pmode)); - if (!FRAME_GROWS_DOWNWARD) - function->x_frame_offset += size; +#ifndef FRAME_GROWS_DOWNWARD + function->x_frame_offset += size; +#endif x = gen_rtx_MEM (mode, addr); - MEM_NOTRAP_P (x) = 1; function->x_stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, x, function->x_stack_slot_list); - if (frame_offset_overflow (function->x_frame_offset, function->decl)) - function->x_frame_offset = 0; - return x; } @@ -509,85 +628,6 @@ assign_stack_local (enum machine_mode mode, HOST_WIDE_INT size, int align) { return assign_stack_local_1 (mode, size, align, cfun); } - - -/* Removes temporary slot TEMP from LIST. */ - -static void -cut_slot_from_list (struct temp_slot *temp, struct temp_slot **list) -{ - if (temp->next) - temp->next->prev = temp->prev; - if (temp->prev) - temp->prev->next = temp->next; - else - *list = temp->next; - - temp->prev = temp->next = NULL; -} - -/* Inserts temporary slot TEMP to LIST. */ - -static void -insert_slot_to_list (struct temp_slot *temp, struct temp_slot **list) -{ - temp->next = *list; - if (*list) - (*list)->prev = temp; - temp->prev = NULL; - *list = temp; -} - -/* Returns the list of used temp slots at LEVEL. */ - -static struct temp_slot ** -temp_slots_at_level (int level) -{ - if (level >= (int) VEC_length (temp_slot_p, used_temp_slots)) - { - size_t old_length = VEC_length (temp_slot_p, used_temp_slots); - temp_slot_p *p; - - VEC_safe_grow (temp_slot_p, gc, used_temp_slots, level + 1); - p = VEC_address (temp_slot_p, used_temp_slots); - memset (&p[old_length], 0, - sizeof (temp_slot_p) * (level + 1 - old_length)); - } - - return &(VEC_address (temp_slot_p, used_temp_slots)[level]); -} - -/* Returns the maximal temporary slot level. */ - -static int -max_slot_level (void) -{ - if (!used_temp_slots) - return -1; - - return VEC_length (temp_slot_p, used_temp_slots) - 1; -} - -/* Moves temporary slot TEMP to LEVEL. */ - -static void -move_slot_to_level (struct temp_slot *temp, int level) -{ - cut_slot_from_list (temp, temp_slots_at_level (temp->level)); - insert_slot_to_list (temp, temp_slots_at_level (level)); - temp->level = level; -} - -/* Make temporary slot TEMP available. */ - -static void -make_slot_available (struct temp_slot *temp) -{ - cut_slot_from_list (temp, temp_slots_at_level (temp->level)); - insert_slot_to_list (temp, &avail_temp_slots); - temp->in_use = 0; - temp->level = -1; -} /* Allocate a temporary stack slot and record it for possible later reuse. @@ -599,26 +639,25 @@ make_slot_available (struct temp_slot *temp) KEEP is 1 if this slot is to be retained after a call to free_temp_slots. Automatic variables for a block are allocated - with this flag. KEEP values of 2 or 3 were needed respectively - for variables whose lifetime is controlled by CLEANUP_POINT_EXPRs - or for SAVE_EXPRs, but they are now unused. + with this flag. KEEP is 2 if we allocate a longer term temporary, + whose lifetime is controlled by CLEANUP_POINT_EXPRs. KEEP is 3 + if we are to allocate something at an inner level to be treated as + a variable in the block (e.g., a SAVE_EXPR). TYPE is the type that will be used for the stack slot. */ rtx -assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, - int keep, tree type) +assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep, + tree type) { unsigned int align; - struct temp_slot *p, *best_p = 0, *selected = NULL, **pp; + struct temp_slot *p, *best_p = 0; rtx slot; /* If SIZE is -1 it means that somebody tried to allocate a temporary of a variable size. */ - gcc_assert (size != -1); - - /* These are now unused. */ - gcc_assert (keep <= 1); + if (size == -1) + abort (); if (mode == BLKmode) align = BIGGEST_ALIGNMENT; @@ -626,46 +665,32 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, align = GET_MODE_ALIGNMENT (mode); if (! type) - type = lang_hooks.types.type_for_mode (mode, 0); + type = (*lang_hooks.types.type_for_mode) (mode, 0); if (type) align = LOCAL_ALIGNMENT (type, align); /* Try to find an available, already-allocated temporary of the proper mode which meets the size and alignment requirements. Choose the - smallest one with the closest alignment. - - If assign_stack_temp is called outside of the tree->rtl expansion, - we cannot reuse the stack slots (that may still refer to - VIRTUAL_STACK_VARS_REGNUM). */ - if (!virtuals_instantiated) - { - for (p = avail_temp_slots; p; p = p->next) - { - if (p->align >= align && p->size >= size - && GET_MODE (p->slot) == mode - && objects_must_conflict_p (p->type, type) - && (best_p == 0 || best_p->size > p->size - || (best_p->size == p->size && best_p->align > p->align))) - { - if (p->align == align && p->size == size) - { - selected = p; - cut_slot_from_list (selected, &avail_temp_slots); - best_p = 0; - break; - } - best_p = p; - } - } - } + smallest one with the closest alignment. */ + for (p = temp_slots; p; p = p->next) + if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode + && ! p->in_use + && objects_must_conflict_p (p->type, type) + && (best_p == 0 || best_p->size > p->size + || (best_p->size == p->size && best_p->align > p->align))) + { + if (p->align == align && p->size == size) + { + best_p = 0; + break; + } + best_p = p; + } /* Make our best, if any, the one to use. */ if (best_p) { - selected = best_p; - cut_slot_from_list (selected, &avail_temp_slots); - /* If there are enough aligned bytes left over, make them into a new temp_slot so that the extra bytes don't get wasted. Do this only for BLKmode slots, so that we can be sure of the alignment. */ @@ -681,11 +706,15 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, p->size = best_p->size - rounded_size; p->base_offset = best_p->base_offset + rounded_size; p->full_size = best_p->full_size - rounded_size; - p->slot = adjust_address_nv (best_p->slot, BLKmode, rounded_size); + p->slot = gen_rtx_MEM (BLKmode, + plus_constant (XEXP (best_p->slot, 0), + rounded_size)); p->align = best_p->align; p->address = 0; + p->rtl_expr = 0; p->type = best_p->type; - insert_slot_to_list (p, &avail_temp_slots); + p->next = temp_slots; + temp_slots = p; stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, p->slot, stack_slot_list); @@ -694,10 +723,12 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, best_p->full_size = rounded_size; } } + + p = best_p; } /* If we still didn't find one, make a new temporary. */ - if (selected == 0) + if (p == 0) { HOST_WIDE_INT frame_offset_old = frame_offset; @@ -710,7 +741,8 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, So for requests which depended on the rounding of SIZE, we go ahead and round it now. We also make sure ALIGNMENT is at least BIGGEST_ALIGNMENT. */ - gcc_assert (mode != BLKmode || align == BIGGEST_ALIGNMENT); + if (mode == BLKmode && align < BIGGEST_ALIGNMENT) + abort (); p->slot = assign_stack_local (mode, (mode == BLKmode ? CEIL_ROUND (size, (int) align / BITS_PER_UNIT) @@ -726,36 +758,46 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, can be either above or below this stack slot depending on which way the frame grows. We include the extra space if and only if it is above this slot. */ - if (FRAME_GROWS_DOWNWARD) - p->size = frame_offset_old - frame_offset; - else - p->size = size; +#ifdef FRAME_GROWS_DOWNWARD + p->size = frame_offset_old - frame_offset; +#else + p->size = size; +#endif /* Now define the fields used by combine_temp_slots. */ - if (FRAME_GROWS_DOWNWARD) - { - p->base_offset = frame_offset; - p->full_size = frame_offset_old - frame_offset; - } - else - { - p->base_offset = frame_offset_old; - p->full_size = frame_offset - frame_offset_old; - } +#ifdef FRAME_GROWS_DOWNWARD + p->base_offset = frame_offset; + p->full_size = frame_offset_old - frame_offset; +#else + p->base_offset = frame_offset_old; + p->full_size = frame_offset - frame_offset_old; +#endif p->address = 0; - - selected = p; + p->next = temp_slots; + temp_slots = p; } - p = selected; p->in_use = 1; p->addr_taken = 0; + p->rtl_expr = seq_rtl_expr; p->type = type; - p->level = temp_slot_level; - p->keep = keep; - pp = temp_slots_at_level (p->level); - insert_slot_to_list (p, pp); + if (keep == 2) + { + p->level = target_temp_slot_level; + p->keep = 1; + } + else if (keep == 3) + { + p->level = var_temp_slot_level; + p->keep = 0; + } + else + { + p->level = temp_slot_level; + p->keep = keep; + } + /* Create a new MEM rtx to avoid clobbering MEM flags of old slots. */ slot = gen_rtx_MEM (mode, XEXP (p->slot, 0)); @@ -770,10 +812,11 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, /* If a type is specified, set the relevant flags. */ if (type != 0) { + RTX_UNCHANGING_P (slot) = (lang_hooks.honor_readonly + && TYPE_READONLY (type)); MEM_VOLATILE_P (slot) = TYPE_VOLATILE (type); MEM_SET_IN_STRUCT_P (slot, AGGREGATE_TYPE_P (type)); } - MEM_NOTRAP_P (slot) = 1; return slot; } @@ -803,7 +846,7 @@ assign_temp (tree type_or_decl, int keep, int memory_required, { tree type, decl; enum machine_mode mode; -#ifdef PROMOTE_MODE +#ifndef PROMOTE_FOR_CALL_ONLY int unsignedp; #endif @@ -813,8 +856,8 @@ assign_temp (tree type_or_decl, int keep, int memory_required, decl = NULL, type = type_or_decl; mode = TYPE_MODE (type); -#ifdef PROMOTE_MODE - unsignedp = TYPE_UNSIGNED (type); +#ifndef PROMOTE_FOR_CALL_ONLY + unsignedp = TREE_UNSIGNED (type); #endif if (mode == BLKmode || memory_required) @@ -828,19 +871,22 @@ assign_temp (tree type_or_decl, int keep, int memory_required, size = 1; /* Unfortunately, we don't yet know how to allocate variable-sized - temporaries. However, sometimes we can find a fixed upper limit on - the size, so try that instead. */ - else if (size == -1) - size = max_int_size_in_bytes (type); + temporaries. However, sometimes we have a fixed upper limit on + the size (which is stored in TYPE_ARRAY_MAX_SIZE) and can use that + instead. This is the case for Chill variable-sized strings. */ + if (size == -1 && TREE_CODE (type) == ARRAY_TYPE + && TYPE_ARRAY_MAX_SIZE (type) != NULL_TREE + && host_integerp (TYPE_ARRAY_MAX_SIZE (type), 1)) + size = tree_low_cst (TYPE_ARRAY_MAX_SIZE (type), 1); /* The size of the temporary may be too large to fit into an integer. */ /* ??? Not sure this should happen except for user silliness, so limit this to things that aren't compiler-generated temporaries. The - rest of the time we'll die in assign_stack_temp_for_type. */ + rest of the time we'll abort in assign_stack_temp_for_type. */ if (decl && size == -1 && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST) { - error ("size of variable %q+D is too large", decl); + error ("%Jsize of variable '%D' is too large", decl, decl); size = 1; } @@ -848,7 +894,7 @@ assign_temp (tree type_or_decl, int keep, int memory_required, return tmp; } -#ifdef PROMOTE_MODE +#ifndef PROMOTE_FOR_CALL_ONLY if (! dont_promote) mode = promote_mode (type, mode, &unsignedp, 0); #endif @@ -862,10 +908,11 @@ assign_temp (tree type_or_decl, int keep, int memory_required, done for BLKmode slots because we can be sure that we won't have alignment problems in this case. */ -static void +void combine_temp_slots (void) { - struct temp_slot *p, *q, *next, *next_q; + struct temp_slot *p, *q; + struct temp_slot *prev_p, *prev_q; int num_slots; /* We can't combine slots, because the information about which slot @@ -876,50 +923,52 @@ combine_temp_slots (void) /* If there are a lot of temp slots, don't do anything unless high levels of optimization. */ if (! flag_expensive_optimizations) - for (p = avail_temp_slots, num_slots = 0; p; p = p->next, num_slots++) + for (p = temp_slots, num_slots = 0; p; p = p->next, num_slots++) if (num_slots > 100 || (num_slots > 10 && optimize == 0)) return; - for (p = avail_temp_slots; p; p = next) + for (p = temp_slots, prev_p = 0; p; p = prev_p ? prev_p->next : temp_slots) { int delete_p = 0; - next = p->next; - - if (GET_MODE (p->slot) != BLKmode) - continue; - - for (q = p->next; q; q = next_q) - { - int delete_q = 0; - - next_q = q->next; - - if (GET_MODE (q->slot) != BLKmode) - continue; - - if (p->base_offset + p->full_size == q->base_offset) - { - /* Q comes after P; combine Q into P. */ - p->size += q->size; - p->full_size += q->full_size; - delete_q = 1; - } - else if (q->base_offset + q->full_size == p->base_offset) - { - /* P comes after Q; combine P into Q. */ - q->size += p->size; - q->full_size += p->full_size; - delete_p = 1; - break; - } - if (delete_q) - cut_slot_from_list (q, &avail_temp_slots); - } - + if (! p->in_use && GET_MODE (p->slot) == BLKmode) + for (q = p->next, prev_q = p; q; q = prev_q->next) + { + int delete_q = 0; + if (! q->in_use && GET_MODE (q->slot) == BLKmode) + { + if (p->base_offset + p->full_size == q->base_offset) + { + /* Q comes after P; combine Q into P. */ + p->size += q->size; + p->full_size += q->full_size; + delete_q = 1; + } + else if (q->base_offset + q->full_size == p->base_offset) + { + /* P comes after Q; combine P into Q. */ + q->size += p->size; + q->full_size += p->full_size; + delete_p = 1; + break; + } + } + /* Either delete Q or advance past it. */ + if (delete_q) + prev_q->next = q->next; + else + prev_q = q; + } /* Either delete P or advance past it. */ if (delete_p) - cut_slot_from_list (p, &avail_temp_slots); + { + if (prev_p) + prev_p->next = p->next; + else + temp_slots = p->next; + } + else + prev_p = p; } } @@ -930,32 +979,33 @@ find_temp_slot_from_address (rtx x) { struct temp_slot *p; rtx next; - int i; - for (i = max_slot_level (); i >= 0; i--) - for (p = *temp_slots_at_level (i); p; p = p->next) - { - if (XEXP (p->slot, 0) == x - || p->address == x - || (GET_CODE (x) == PLUS - && XEXP (x, 0) == virtual_stack_vars_rtx - && GET_CODE (XEXP (x, 1)) == CONST_INT - && INTVAL (XEXP (x, 1)) >= p->base_offset - && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size)) - return p; - - else if (p->address != 0 && GET_CODE (p->address) == EXPR_LIST) - for (next = p->address; next; next = XEXP (next, 1)) - if (XEXP (next, 0) == x) - return p; - } + for (p = temp_slots; p; p = p->next) + { + if (! p->in_use) + continue; + + else if (XEXP (p->slot, 0) == x + || p->address == x + || (GET_CODE (x) == PLUS + && XEXP (x, 0) == virtual_stack_vars_rtx + && GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= p->base_offset + && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size)) + return p; + + else if (p->address != 0 && GET_CODE (p->address) == EXPR_LIST) + for (next = p->address; next; next = XEXP (next, 1)) + if (XEXP (next, 0) == x) + return p; + } /* If we have a sum involving a register, see if it points to a temp slot. */ - if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) + if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG && (p = find_temp_slot_from_address (XEXP (x, 0))) != 0) return p; - else if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 1)) + else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG && (p = find_temp_slot_from_address (XEXP (x, 1))) != 0) return p; @@ -985,7 +1035,7 @@ update_temp_slot_address (rtx old, rtx new) if (GET_CODE (old) != PLUS) return; - if (REG_P (new)) + if (GET_CODE (new) == REG) { update_temp_slot_address (XEXP (old, 0), new); update_temp_slot_address (XEXP (old, 1), new); @@ -1031,7 +1081,7 @@ mark_temp_addr_taken (rtx x) /* If X is not in memory or is at a constant address, it cannot be in a temporary slot. */ - if (!MEM_P (x) || CONSTANT_P (XEXP (x, 0))) + if (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0))) return; p = find_temp_slot_from_address (XEXP (x, 0)); @@ -1051,19 +1101,15 @@ mark_temp_addr_taken (rtx x) void preserve_temp_slots (rtx x) { - struct temp_slot *p = 0, *next; + struct temp_slot *p = 0; /* If there is no result, we still might have some objects whose address were taken, so we need to make sure they stay around. */ if (x == 0) { - for (p = *temp_slots_at_level (temp_slot_level); p; p = next) - { - next = p->next; - - if (p->addr_taken) - move_slot_to_level (p, temp_slot_level - 1); - } + for (p = temp_slots; p; p = p->next) + if (p->in_use && p->level == temp_slot_level && p->addr_taken) + p->level--; return; } @@ -1072,21 +1118,17 @@ preserve_temp_slots (rtx x) a temporary slot we know it points to. To be consistent with the code below, we really should preserve all non-kept slots if we can't find a match, but that seems to be much too costly. */ - if (REG_P (x) && REG_POINTER (x)) + if (GET_CODE (x) == REG && REG_POINTER (x)) p = find_temp_slot_from_address (x); /* If X is not in memory or is at a constant address, it cannot be in a temporary slot, but it can contain something whose address was taken. */ - if (p == 0 && (!MEM_P (x) || CONSTANT_P (XEXP (x, 0)))) + if (p == 0 && (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))) { - for (p = *temp_slots_at_level (temp_slot_level); p; p = next) - { - next = p->next; - - if (p->addr_taken) - move_slot_to_level (p, temp_slot_level - 1); - } + for (p = temp_slots; p; p = p->next) + if (p->in_use && p->level == temp_slot_level && p->addr_taken) + p->level--; return; } @@ -1103,49 +1145,107 @@ preserve_temp_slots (rtx x) if (p->level == temp_slot_level) { - for (q = *temp_slots_at_level (temp_slot_level); q; q = next) - { - next = q->next; + for (q = temp_slots; q; q = q->next) + if (q != p && q->addr_taken && q->level == p->level) + q->level--; - if (p != q && q->addr_taken) - move_slot_to_level (q, temp_slot_level - 1); - } - - move_slot_to_level (p, temp_slot_level - 1); + p->level--; p->addr_taken = 0; } return; } /* Otherwise, preserve all non-kept slots at this level. */ - for (p = *temp_slots_at_level (temp_slot_level); p; p = next) - { - next = p->next; + for (p = temp_slots; p; p = p->next) + if (p->in_use && p->level == temp_slot_level && ! p->keep) + p->level--; +} + +/* X is the result of an RTL_EXPR. If it is a temporary slot associated + with that RTL_EXPR, promote it into a temporary slot at the present + level so it will not be freed when we free slots made in the + RTL_EXPR. */ + +void +preserve_rtl_expr_result (rtx x) +{ + struct temp_slot *p; + + /* If X is not in memory or is at a constant address, it cannot be in + a temporary slot. */ + if (x == 0 || GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0))) + return; - if (!p->keep) - move_slot_to_level (p, temp_slot_level - 1); + /* If we can find a match, move it to our level unless it is already at + an upper level. */ + p = find_temp_slot_from_address (XEXP (x, 0)); + if (p != 0) + { + p->level = MIN (p->level, temp_slot_level); + p->rtl_expr = 0; } + + return; } -/* Free all temporaries used so far. This is normally called at the - end of generating code for a statement. */ +/* Free all temporaries used so far. This is normally called at the end + of generating code for a statement. Don't free any temporaries + currently in use for an RTL_EXPR that hasn't yet been emitted. + We could eventually do better than this since it can be reused while + generating the same RTL_EXPR, but this is complex and probably not + worthwhile. */ void free_temp_slots (void) { - struct temp_slot *p, *next; + struct temp_slot *p; - for (p = *temp_slots_at_level (temp_slot_level); p; p = next) - { - next = p->next; + for (p = temp_slots; p; p = p->next) + if (p->in_use && p->level == temp_slot_level && ! p->keep + && p->rtl_expr == 0) + p->in_use = 0; - if (!p->keep) - make_slot_available (p); - } + combine_temp_slots (); +} + +/* Free all temporary slots used in T, an RTL_EXPR node. */ + +void +free_temps_for_rtl_expr (tree t) +{ + struct temp_slot *p; + + for (p = temp_slots; p; p = p->next) + if (p->rtl_expr == t) + { + /* If this slot is below the current TEMP_SLOT_LEVEL, then it + needs to be preserved. This can happen if a temporary in + the RTL_EXPR was addressed; preserve_temp_slots will move + the temporary into a higher level. */ + if (temp_slot_level <= p->level) + p->in_use = 0; + else + p->rtl_expr = NULL_TREE; + } combine_temp_slots (); } +/* Mark all temporaries ever allocated in this function as not suitable + for reuse until the current level is exited. */ + +void +mark_all_temps_used (void) +{ + struct temp_slot *p; + + for (p = temp_slots; p; p = p->next) + { + p->in_use = p->keep = 1; + p->level = MIN (p->level, temp_slot_level); + } +} + /* Push deeper into the nesting level for stack temporaries. */ void @@ -1160,13 +1260,11 @@ push_temp_slots (void) void pop_temp_slots (void) { - struct temp_slot *p, *next; + struct temp_slot *p; - for (p = *temp_slots_at_level (temp_slot_level); p; p = next) - { - next = p->next; - make_slot_available (p); - } + for (p = temp_slots; p; p = p->next) + if (p->in_use && p->level == temp_slot_level && p->rtl_expr == 0) + p->in_use = 0; combine_temp_slots (); @@ -1179,1912 +1277,4067 @@ void init_temp_slots (void) { /* We have not allocated any temporaries yet. */ - avail_temp_slots = 0; - used_temp_slots = 0; + temp_slots = 0; temp_slot_level = 0; + var_temp_slot_level = 0; + target_temp_slot_level = 0; } -/* These routines are responsible for converting virtual register references - to the actual hard register references once RTL generation is complete. +/* Retroactively move an auto variable from a register to a stack + slot. This is done when an address-reference to the variable is + seen. If RESCAN is true, all previously emitted instructions are + examined and modified to handle the fact that DECL is now + addressable. */ - The following four variables are used for communication between the - routines. They contain the offsets of the virtual registers from their - respective hard registers. */ +void +put_var_into_stack (tree decl, int rescan) +{ + rtx reg; + enum machine_mode promoted_mode, decl_mode; + struct function *function = 0; + tree context; + bool can_use_addressof_p; + bool volatile_p = TREE_CODE (decl) != SAVE_EXPR && TREE_THIS_VOLATILE (decl); + bool used_p = (TREE_USED (decl) + || (TREE_CODE (decl) != SAVE_EXPR && DECL_INITIAL (decl) != 0)); + + context = decl_function_context (decl); + + /* Get the current rtl used for this object and its original mode. */ + reg = (TREE_CODE (decl) == SAVE_EXPR + ? SAVE_EXPR_RTL (decl) + : DECL_RTL_IF_SET (decl)); + + /* No need to do anything if decl has no rtx yet + since in that case caller is setting TREE_ADDRESSABLE + and a stack slot will be assigned when the rtl is made. */ + if (reg == 0) + return; -static int in_arg_offset; -static int var_offset; -static int dynamic_offset; -static int out_arg_offset; -static int cfa_offset; + /* Get the declared mode for this object. */ + decl_mode = (TREE_CODE (decl) == SAVE_EXPR ? TYPE_MODE (TREE_TYPE (decl)) + : DECL_MODE (decl)); + /* Get the mode it's actually stored in. */ + promoted_mode = GET_MODE (reg); + + /* If this variable comes from an outer function, find that + function's saved context. Don't use find_function_data here, + because it might not be in any active function. + FIXME: Is that really supposed to happen? + It does in ObjC at least. */ + if (context != current_function_decl && context != inline_function_decl) + for (function = outer_function_chain; function; function = function->outer) + if (function->decl == context) + break; -/* In most machines, the stack pointer register is equivalent to the bottom - of the stack. */ + /* If this is a variable-sized object or a structure passed by invisible + reference, with a pseudo to address it, put that pseudo into the stack + if the var is non-local. */ + if (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl) + && GET_CODE (reg) == MEM + && GET_CODE (XEXP (reg, 0)) == REG + && REGNO (XEXP (reg, 0)) > LAST_VIRTUAL_REGISTER) + { + reg = XEXP (reg, 0); + decl_mode = promoted_mode = GET_MODE (reg); + } -#ifndef STACK_POINTER_OFFSET -#define STACK_POINTER_OFFSET 0 + /* If this variable lives in the current function and we don't need to put it + in the stack for the sake of setjmp or the non-locality, try to keep it in + a register until we know we actually need the address. */ + can_use_addressof_p + = (function == 0 + && ! (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl)) + && optimize > 0 + /* FIXME make it work for promoted modes too */ + && decl_mode == promoted_mode +#ifdef NON_SAVING_SETJMP + && ! (NON_SAVING_SETJMP && current_function_calls_setjmp) #endif + ); -/* If not defined, pick an appropriate default for the offset of dynamically - allocated memory depending on the value of ACCUMULATE_OUTGOING_ARGS, - REG_PARM_STACK_SPACE, and OUTGOING_REG_PARM_STACK_SPACE. */ - -#ifndef STACK_DYNAMIC_OFFSET - -/* The bottom of the stack points to the actual arguments. If - REG_PARM_STACK_SPACE is defined, this includes the space for the register - parameters. However, if OUTGOING_REG_PARM_STACK space is not defined, - stack space for register parameters is not pushed by the caller, but - rather part of the fixed stack areas and hence not included in - `current_function_outgoing_args_size'. Nevertheless, we must allow - for it when allocating stack dynamic objects. */ + /* If we can't use ADDRESSOF, make sure we see through one we already + generated. */ + if (! can_use_addressof_p + && GET_CODE (reg) == MEM + && GET_CODE (XEXP (reg, 0)) == ADDRESSOF) + reg = XEXP (XEXP (reg, 0), 0); -#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE) -#define STACK_DYNAMIC_OFFSET(FNDECL) \ -((ACCUMULATE_OUTGOING_ARGS \ - ? (current_function_outgoing_args_size + REG_PARM_STACK_SPACE (FNDECL)) : 0)\ - + (STACK_POINTER_OFFSET)) \ + /* Now we should have a value that resides in one or more pseudo regs. */ + if (GET_CODE (reg) == REG) + { + if (can_use_addressof_p) + gen_mem_addressof (reg, decl, rescan); + else + put_reg_into_stack (function, reg, TREE_TYPE (decl), decl_mode, + 0, volatile_p, used_p, false, 0); + } + else if (GET_CODE (reg) == CONCAT) + { + /* A CONCAT contains two pseudos; put them both in the stack. + We do it so they end up consecutive. + We fixup references to the parts only after we fixup references + to the whole CONCAT, lest we do double fixups for the latter + references. */ + enum machine_mode part_mode = GET_MODE (XEXP (reg, 0)); + tree part_type = (*lang_hooks.types.type_for_mode) (part_mode, 0); + rtx lopart = XEXP (reg, 0); + rtx hipart = XEXP (reg, 1); +#ifdef FRAME_GROWS_DOWNWARD + /* Since part 0 should have a lower address, do it second. */ + put_reg_into_stack (function, hipart, part_type, part_mode, + 0, volatile_p, false, false, 0); + put_reg_into_stack (function, lopart, part_type, part_mode, + 0, volatile_p, false, true, 0); #else -#define STACK_DYNAMIC_OFFSET(FNDECL) \ -((ACCUMULATE_OUTGOING_ARGS ? current_function_outgoing_args_size : 0) \ - + (STACK_POINTER_OFFSET)) -#endif + put_reg_into_stack (function, lopart, part_type, part_mode, + 0, volatile_p, false, false, 0); + put_reg_into_stack (function, hipart, part_type, part_mode, + 0, volatile_p, false, true, 0); #endif - -/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX - is a virtual register, return the equivalent hard register and set the - offset indirectly through the pointer. Otherwise, return 0. */ + /* Change the CONCAT into a combined MEM for both parts. */ + PUT_CODE (reg, MEM); + MEM_ATTRS (reg) = 0; + + /* set_mem_attributes uses DECL_RTL to avoid re-generating of + already computed alias sets. Here we want to re-generate. */ + if (DECL_P (decl)) + SET_DECL_RTL (decl, NULL); + set_mem_attributes (reg, decl, 1); + if (DECL_P (decl)) + SET_DECL_RTL (decl, reg); + + /* The two parts are in memory order already. + Use the lower parts address as ours. */ + XEXP (reg, 0) = XEXP (XEXP (reg, 0), 0); + /* Prevent sharing of rtl that might lose. */ + if (GET_CODE (XEXP (reg, 0)) == PLUS) + XEXP (reg, 0) = copy_rtx (XEXP (reg, 0)); + if (used_p && rescan) + { + schedule_fixup_var_refs (function, reg, TREE_TYPE (decl), + promoted_mode, 0); + schedule_fixup_var_refs (function, lopart, part_type, part_mode, 0); + schedule_fixup_var_refs (function, hipart, part_type, part_mode, 0); + } + } + else + return; +} -static rtx -instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset) +/* Subroutine of put_var_into_stack. This puts a single pseudo reg REG + into the stack frame of FUNCTION (0 means the current function). + TYPE is the user-level data type of the value hold in the register. + DECL_MODE is the machine mode of the user-level data type. + ORIGINAL_REGNO must be set if the real regno is not visible in REG. + VOLATILE_P is true if this is for a "volatile" decl. + USED_P is true if this reg might have already been used in an insn. + CONSECUTIVE_P is true if the stack slot assigned to reg must be + consecutive with the previous stack slot. */ + +static void +put_reg_into_stack (struct function *function, rtx reg, tree type, + enum machine_mode decl_mode, unsigned int original_regno, + bool volatile_p, bool used_p, bool consecutive_p, + htab_t ht) { - rtx new; - HOST_WIDE_INT offset; + struct function *func = function ? function : cfun; + enum machine_mode mode = GET_MODE (reg); + unsigned int regno = original_regno; + rtx new = 0; - if (x == virtual_incoming_args_rtx) - new = arg_pointer_rtx, offset = in_arg_offset; - else if (x == virtual_stack_vars_rtx) - new = frame_pointer_rtx, offset = var_offset; - else if (x == virtual_stack_dynamic_rtx) - new = stack_pointer_rtx, offset = dynamic_offset; - else if (x == virtual_outgoing_args_rtx) - new = stack_pointer_rtx, offset = out_arg_offset; - else if (x == virtual_cfa_rtx) + if (regno == 0) + regno = REGNO (reg); + + if (regno < func->x_max_parm_reg) { -#ifdef FRAME_POINTER_CFA_OFFSET - new = frame_pointer_rtx; -#else - new = arg_pointer_rtx; -#endif - offset = cfa_offset; + if (!func->x_parm_reg_stack_loc) + abort (); + new = func->x_parm_reg_stack_loc[regno]; } - else - return NULL_RTX; - *poffset = offset; - return new; + if (new == 0) + new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), + consecutive_p ? -2 : 0, func); + + PUT_CODE (reg, MEM); + PUT_MODE (reg, decl_mode); + XEXP (reg, 0) = XEXP (new, 0); + MEM_ATTRS (reg) = 0; + /* `volatil' bit means one thing for MEMs, another entirely for REGs. */ + MEM_VOLATILE_P (reg) = volatile_p; + + /* If this is a memory ref that contains aggregate components, + mark it as such for cse and loop optimize. If we are reusing a + previously generated stack slot, then we need to copy the bit in + case it was set for other reasons. For instance, it is set for + __builtin_va_alist. */ + if (type) + { + MEM_SET_IN_STRUCT_P (reg, + AGGREGATE_TYPE_P (type) || MEM_IN_STRUCT_P (new)); + set_mem_alias_set (reg, get_alias_set (type)); + } + + if (used_p) + schedule_fixup_var_refs (function, reg, type, mode, ht); } -/* A subroutine of instantiate_virtual_regs, called via for_each_rtx. - Instantiate any virtual registers present inside of *LOC. The expression - is simplified, as much as possible, but is not to be considered "valid" - in any sense implied by the target. If any change is made, set CHANGED - to true. */ +/* Make sure that all refs to the variable, previously made + when it was a register, are fixed up to be valid again. + See function above for meaning of arguments. */ -static int -instantiate_virtual_regs_in_rtx (rtx *loc, void *data) +static void +schedule_fixup_var_refs (struct function *function, rtx reg, tree type, + enum machine_mode promoted_mode, htab_t ht) { - HOST_WIDE_INT offset; - bool *changed = (bool *) data; - rtx x, new; + int unsigned_p = type ? TREE_UNSIGNED (type) : 0; - x = *loc; - if (x == 0) - return 0; + if (function != 0) + { + struct var_refs_queue *temp; + + temp = ggc_alloc (sizeof (struct var_refs_queue)); + temp->modified = reg; + temp->promoted_mode = promoted_mode; + temp->unsignedp = unsigned_p; + temp->next = function->fixup_var_refs_queue; + function->fixup_var_refs_queue = temp; + } + else + /* Variable is local; fix it up now. */ + fixup_var_refs (reg, promoted_mode, unsigned_p, reg, ht); +} + +static void +fixup_var_refs (rtx var, enum machine_mode promoted_mode, int unsignedp, + rtx may_share, htab_t ht) +{ + tree pending; + rtx first_insn = get_insns (); + struct sequence_stack *stack = seq_stack; + tree rtl_exps = rtl_expr_chain; - switch (GET_CODE (x)) + /* If there's a hash table, it must record all uses of VAR. */ + if (ht) { - case REG: - new = instantiate_new_reg (x, &offset); - if (new) - { - *loc = plus_constant (new, offset); - if (changed) - *changed = true; - } - return -1; + if (stack != 0) + abort (); + fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp, + may_share); + return; + } - case PLUS: - new = instantiate_new_reg (XEXP (x, 0), &offset); - if (new) + fixup_var_refs_insns (first_insn, var, promoted_mode, unsignedp, + stack == 0, may_share); + + /* Scan all pending sequences too. */ + for (; stack; stack = stack->next) + { + push_to_full_sequence (stack->first, stack->last); + fixup_var_refs_insns (stack->first, var, promoted_mode, unsignedp, + stack->next != 0, may_share); + /* Update remembered end of sequence + in case we added an insn at the end. */ + stack->last = get_last_insn (); + end_sequence (); + } + + /* Scan all waiting RTL_EXPRs too. */ + for (pending = rtl_exps; pending; pending = TREE_CHAIN (pending)) + { + rtx seq = RTL_EXPR_SEQUENCE (TREE_VALUE (pending)); + if (seq != const0_rtx && seq != 0) { - new = plus_constant (new, offset); - *loc = simplify_gen_binary (PLUS, GET_MODE (x), new, XEXP (x, 1)); - if (changed) - *changed = true; - return -1; + push_to_sequence (seq); + fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0, + may_share); + end_sequence (); } + } +} + +/* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is + some part of an insn. Return a struct fixup_replacement whose OLD + value is equal to X. Allocate a new structure if no such entry exists. */ - /* FIXME -- from old code */ - /* If we have (plus (subreg (virtual-reg)) (const_int)), we know - we can commute the PLUS and SUBREG because pointers into the - frame are well-behaved. */ - break; +static struct fixup_replacement * +find_fixup_replacement (struct fixup_replacement **replacements, rtx x) +{ + struct fixup_replacement *p; - default: - break; + /* See if we have already replaced this. */ + for (p = *replacements; p != 0 && ! rtx_equal_p (p->old, x); p = p->next) + ; + + if (p == 0) + { + p = xmalloc (sizeof (struct fixup_replacement)); + p->old = x; + p->new = 0; + p->next = *replacements; + *replacements = p; } - return 0; + return p; } -/* A subroutine of instantiate_virtual_regs_in_insn. Return true if X - matches the predicate for insn CODE operand OPERAND. */ +/* Scan the insn-chain starting with INSN for refs to VAR and fix them + up. TOPLEVEL is nonzero if this chain is the main chain of insns + for the current function. MAY_SHARE is either a MEM that is not + to be unshared or a list of them. */ -static int -safe_insn_predicate (int code, int operand, rtx x) +static void +fixup_var_refs_insns (rtx insn, rtx var, enum machine_mode promoted_mode, + int unsignedp, int toplevel, rtx may_share) { - const struct insn_operand_data *op_data; + while (insn) + { + /* fixup_var_refs_insn might modify insn, so save its next + pointer now. */ + rtx next = NEXT_INSN (insn); - if (code < 0) - return true; + /* CALL_PLACEHOLDERs are special; we have to switch into each of + the three sequences they (potentially) contain, and process + them recursively. The CALL_INSN itself is not interesting. */ - op_data = &insn_data[code].operand[operand]; - if (op_data->predicate == NULL) - return true; + if (GET_CODE (insn) == CALL_INSN + && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) + { + int i; + + /* Look at the Normal call, sibling call and tail recursion + sequences attached to the CALL_PLACEHOLDER. */ + for (i = 0; i < 3; i++) + { + rtx seq = XEXP (PATTERN (insn), i); + if (seq) + { + push_to_sequence (seq); + fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0, + may_share); + XEXP (PATTERN (insn), i) = get_insns (); + end_sequence (); + } + } + } + + else if (INSN_P (insn)) + fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel, + may_share); - return op_data->predicate (x, op_data->mode); + insn = next; + } } -/* A subroutine of instantiate_virtual_regs. Instantiate any virtual - registers present inside of insn. The result will be a valid insn. */ +/* Look up the insns which reference VAR in HT and fix them up. Other + arguments are the same as fixup_var_refs_insns. + + N.B. No need for special processing of CALL_PLACEHOLDERs here, + because the hash table will point straight to the interesting insn + (inside the CALL_PLACEHOLDER). */ static void -instantiate_virtual_regs_in_insn (rtx insn) +fixup_var_refs_insns_with_hash (htab_t ht, rtx var, enum machine_mode promoted_mode, + int unsignedp, rtx may_share) { - HOST_WIDE_INT offset; - int insn_code, i; - bool any_change = false; - rtx set, new, x, seq; + struct insns_for_mem_entry tmp; + struct insns_for_mem_entry *ime; + rtx insn_list; + + tmp.key = var; + ime = htab_find (ht, &tmp); + for (insn_list = ime->insns; insn_list != 0; insn_list = XEXP (insn_list, 1)) + if (INSN_P (XEXP (insn_list, 0)) && !INSN_DELETED_P (XEXP (insn_list, 0))) + fixup_var_refs_insn (XEXP (insn_list, 0), var, promoted_mode, + unsignedp, 1, may_share); +} + - /* There are some special cases to be handled first. */ - set = single_set (insn); - if (set) +/* Per-insn processing by fixup_var_refs_insns(_with_hash). INSN is + the insn under examination, VAR is the variable to fix up + references to, PROMOTED_MODE and UNSIGNEDP describe VAR, and + TOPLEVEL is nonzero if this is the main insn chain for this + function. */ + +static void +fixup_var_refs_insn (rtx insn, rtx var, enum machine_mode promoted_mode, + int unsignedp, int toplevel, rtx no_share) +{ + rtx call_dest = 0; + rtx set, prev, prev_set; + rtx note; + + /* Remember the notes in case we delete the insn. */ + note = REG_NOTES (insn); + + /* If this is a CLOBBER of VAR, delete it. + + If it has a REG_LIBCALL note, delete the REG_LIBCALL + and REG_RETVAL notes too. */ + if (GET_CODE (PATTERN (insn)) == CLOBBER + && (XEXP (PATTERN (insn), 0) == var + || (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT + && (XEXP (XEXP (PATTERN (insn), 0), 0) == var + || XEXP (XEXP (PATTERN (insn), 0), 1) == var)))) + { + if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0) + /* The REG_LIBCALL note will go away since we are going to + turn INSN into a NOTE, so just delete the + corresponding REG_RETVAL note. */ + remove_note (XEXP (note, 0), + find_reg_note (XEXP (note, 0), REG_RETVAL, + NULL_RTX)); + + delete_insn (insn); + } + + /* The insn to load VAR from a home in the arglist + is now a no-op. When we see it, just delete it. + Similarly if this is storing VAR from a register from which + it was loaded in the previous insn. This will occur + when an ADDRESSOF was made for an arglist slot. */ + else if (toplevel + && (set = single_set (insn)) != 0 + && SET_DEST (set) == var + /* If this represents the result of an insn group, + don't delete the insn. */ + && find_reg_note (insn, REG_RETVAL, NULL_RTX) == 0 + && (rtx_equal_p (SET_SRC (set), var) + || (GET_CODE (SET_SRC (set)) == REG + && (prev = prev_nonnote_insn (insn)) != 0 + && (prev_set = single_set (prev)) != 0 + && SET_DEST (prev_set) == SET_SRC (set) + && rtx_equal_p (SET_SRC (prev_set), var)))) + { + delete_insn (insn); + } + else { - /* We're allowed to assign to a virtual register. This is interpreted - to mean that the underlying register gets assigned the inverse - transformation. This is used, for example, in the handling of - non-local gotos. */ - new = instantiate_new_reg (SET_DEST (set), &offset); - if (new) + struct fixup_replacement *replacements = 0; + rtx next_insn = NEXT_INSN (insn); + + if (SMALL_REGISTER_CLASSES) { - start_sequence (); + /* If the insn that copies the results of a CALL_INSN + into a pseudo now references VAR, we have to use an + intermediate pseudo since we want the life of the + return value register to be only a single insn. + + If we don't use an intermediate pseudo, such things as + address computations to make the address of VAR valid + if it is not can be placed between the CALL_INSN and INSN. + + To make sure this doesn't happen, we record the destination + of the CALL_INSN and see if the next insn uses both that + and VAR. */ + + if (call_dest != 0 && GET_CODE (insn) == INSN + && reg_mentioned_p (var, PATTERN (insn)) + && reg_mentioned_p (call_dest, PATTERN (insn))) + { + rtx temp = gen_reg_rtx (GET_MODE (call_dest)); - for_each_rtx (&SET_SRC (set), instantiate_virtual_regs_in_rtx, NULL); - x = simplify_gen_binary (PLUS, GET_MODE (new), SET_SRC (set), - GEN_INT (-offset)); - x = force_operand (x, new); - if (x != new) - emit_move_insn (new, x); + emit_insn_before (gen_move_insn (temp, call_dest), insn); - seq = get_insns (); - end_sequence (); + PATTERN (insn) = replace_rtx (PATTERN (insn), + call_dest, temp); + } - emit_insn_before (seq, insn); - delete_insn (insn); - return; + if (GET_CODE (insn) == CALL_INSN + && GET_CODE (PATTERN (insn)) == SET) + call_dest = SET_DEST (PATTERN (insn)); + else if (GET_CODE (insn) == CALL_INSN + && GET_CODE (PATTERN (insn)) == PARALLEL + && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) + call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0)); + else + call_dest = 0; } - /* Handle a straight copy from a virtual register by generating a - new add insn. The difference between this and falling through - to the generic case is avoiding a new pseudo and eliminating a - move insn in the initial rtl stream. */ - new = instantiate_new_reg (SET_SRC (set), &offset); - if (new && offset != 0 - && REG_P (SET_DEST (set)) - && REGNO (SET_DEST (set)) > LAST_VIRTUAL_REGISTER) + /* See if we have to do anything to INSN now that VAR is in + memory. If it needs to be loaded into a pseudo, use a single + pseudo for the entire insn in case there is a MATCH_DUP + between two operands. We pass a pointer to the head of + a list of struct fixup_replacements. If fixup_var_refs_1 + needs to allocate pseudos or replacement MEMs (for SUBREGs), + it will record them in this list. + + If it allocated a pseudo for any replacement, we copy into + it here. */ + + fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn, + &replacements, no_share); + + /* If this is last_parm_insn, and any instructions were output + after it to fix it up, then we must set last_parm_insn to + the last such instruction emitted. */ + if (insn == last_parm_insn) + last_parm_insn = PREV_INSN (next_insn); + + while (replacements) { - start_sequence (); + struct fixup_replacement *next; + + if (GET_CODE (replacements->new) == REG) + { + rtx insert_before; + rtx seq; + + /* OLD might be a (subreg (mem)). */ + if (GET_CODE (replacements->old) == SUBREG) + replacements->old + = fixup_memory_subreg (replacements->old, insn, + promoted_mode, 0); + else + replacements->old + = fixup_stack_1 (replacements->old, insn); - x = expand_simple_binop (GET_MODE (SET_DEST (set)), PLUS, - new, GEN_INT (offset), SET_DEST (set), - 1, OPTAB_LIB_WIDEN); - if (x != SET_DEST (set)) - emit_move_insn (SET_DEST (set), x); + insert_before = insn; - seq = get_insns (); - end_sequence (); + /* If we are changing the mode, do a conversion. + This might be wasteful, but combine.c will + eliminate much of the waste. */ - emit_insn_before (seq, insn); - delete_insn (insn); - return; + if (GET_MODE (replacements->new) + != GET_MODE (replacements->old)) + { + start_sequence (); + convert_move (replacements->new, + replacements->old, unsignedp); + seq = get_insns (); + end_sequence (); + } + else + seq = gen_move_insn (replacements->new, + replacements->old); + + emit_insn_before (seq, insert_before); + } + + next = replacements->next; + free (replacements); + replacements = next; } + } + + /* Also fix up any invalid exprs in the REG_NOTES of this insn. + But don't touch other insns referred to by reg-notes; + we will get them elsewhere. */ + while (note) + { + if (GET_CODE (note) != INSN_LIST) + XEXP (note, 0) + = walk_fixup_memory_subreg (XEXP (note, 0), insn, + promoted_mode, 1); + note = XEXP (note, 1); + } +} + +/* VAR is a MEM that used to be a pseudo register with mode PROMOTED_MODE. + See if the rtx expression at *LOC in INSN needs to be changed. + + REPLACEMENTS is a pointer to a list head that starts out zero, but may + contain a list of original rtx's and replacements. If we find that we need + to modify this insn by replacing a memory reference with a pseudo or by + making a new MEM to implement a SUBREG, we consult that list to see if + we have already chosen a replacement. If none has already been allocated, + we allocate it and update the list. fixup_var_refs_insn will copy VAR + or the SUBREG, as appropriate, to the pseudo. */ + +static void +fixup_var_refs_1 (rtx var, enum machine_mode promoted_mode, rtx *loc, rtx insn, + struct fixup_replacement **replacements, rtx no_share) +{ + int i; + rtx x = *loc; + RTX_CODE code = GET_CODE (x); + const char *fmt; + rtx tem, tem1; + struct fixup_replacement *replacement; - extract_insn (insn); - insn_code = INSN_CODE (insn); - - /* Handle a plus involving a virtual register by determining if the - operands remain valid if they're modified in place. */ - if (GET_CODE (SET_SRC (set)) == PLUS - && recog_data.n_operands >= 3 - && recog_data.operand_loc[1] == &XEXP (SET_SRC (set), 0) - && recog_data.operand_loc[2] == &XEXP (SET_SRC (set), 1) - && GET_CODE (recog_data.operand[2]) == CONST_INT - && (new = instantiate_new_reg (recog_data.operand[1], &offset))) + switch (code) + { + case ADDRESSOF: + if (XEXP (x, 0) == var) { - offset += INTVAL (recog_data.operand[2]); + /* Prevent sharing of rtl that might lose. */ + rtx sub = copy_rtx (XEXP (var, 0)); - /* If the sum is zero, then replace with a plain move. */ - if (offset == 0 - && REG_P (SET_DEST (set)) - && REGNO (SET_DEST (set)) > LAST_VIRTUAL_REGISTER) + if (! validate_change (insn, loc, sub, 0)) { + rtx y = gen_reg_rtx (GET_MODE (sub)); + rtx seq, new_insn; + + /* We should be able to replace with a register or all is lost. + Note that we can't use validate_change to verify this, since + we're not caring for replacing all dups simultaneously. */ + if (! validate_replace_rtx (*loc, y, insn)) + abort (); + + /* Careful! First try to recognize a direct move of the + value, mimicking how things are done in gen_reload wrt + PLUS. Consider what happens when insn is a conditional + move instruction and addsi3 clobbers flags. */ + start_sequence (); - emit_move_insn (SET_DEST (set), new); + new_insn = emit_insn (gen_rtx_SET (VOIDmode, y, sub)); seq = get_insns (); end_sequence (); + if (recog_memoized (new_insn) < 0) + { + /* That failed. Fall back on force_operand and hope. */ + + start_sequence (); + sub = force_operand (sub, y); + if (sub != y) + emit_insn (gen_move_insn (y, sub)); + seq = get_insns (); + end_sequence (); + } + +#ifdef HAVE_cc0 + /* Don't separate setter from user. */ + if (PREV_INSN (insn) && sets_cc0_p (PREV_INSN (insn))) + insn = PREV_INSN (insn); +#endif + emit_insn_before (seq, insn); - delete_insn (insn); - return; } + } + return; - x = gen_int_mode (offset, recog_data.operand_mode[2]); + case MEM: + if (var == x) + { + /* If we already have a replacement, use it. Otherwise, + try to fix up this address in case it is invalid. */ - /* Using validate_change and apply_change_group here leaves - recog_data in an invalid state. Since we know exactly what - we want to check, do those two by hand. */ - if (safe_insn_predicate (insn_code, 1, new) - && safe_insn_predicate (insn_code, 2, x)) + replacement = find_fixup_replacement (replacements, var); + if (replacement->new) { - *recog_data.operand_loc[1] = recog_data.operand[1] = new; - *recog_data.operand_loc[2] = recog_data.operand[2] = x; - any_change = true; - - /* Fall through into the regular operand fixup loop in - order to take care of operands other than 1 and 2. */ + *loc = replacement->new; + return; } + + *loc = replacement->new = x = fixup_stack_1 (x, insn); + + /* Unless we are forcing memory to register or we changed the mode, + we can leave things the way they are if the insn is valid. */ + + INSN_CODE (insn) = -1; + if (! flag_force_mem && GET_MODE (x) == promoted_mode + && recog_memoized (insn) >= 0) + return; + + *loc = replacement->new = gen_reg_rtx (promoted_mode); + return; } - } - else - { - extract_insn (insn); - insn_code = INSN_CODE (insn); - } - /* In the general case, we expect virtual registers to appear only in - operands, and then only as either bare registers or inside memories. */ - for (i = 0; i < recog_data.n_operands; ++i) - { - x = recog_data.operand[i]; - switch (GET_CODE (x)) + /* If X contains VAR, we need to unshare it here so that we update + each occurrence separately. But all identical MEMs in one insn + must be replaced with the same rtx because of the possibility of + MATCH_DUPs. */ + + if (reg_mentioned_p (var, x)) { - case MEM: - { - rtx addr = XEXP (x, 0); - bool changed = false; + replacement = find_fixup_replacement (replacements, x); + if (replacement->new == 0) + replacement->new = copy_most_rtx (x, no_share); - for_each_rtx (&addr, instantiate_virtual_regs_in_rtx, &changed); - if (!changed) - continue; + *loc = x = replacement->new; + code = GET_CODE (x); + } + break; - start_sequence (); - x = replace_equiv_address (x, addr); - seq = get_insns (); - end_sequence (); - if (seq) - emit_insn_before (seq, insn); - } - break; + case REG: + case CC0: + case PC: + case CONST_INT: + case CONST: + case SYMBOL_REF: + case LABEL_REF: + case CONST_DOUBLE: + case CONST_VECTOR: + return; + + case SIGN_EXTRACT: + case ZERO_EXTRACT: + /* Note that in some cases those types of expressions are altered + by optimize_bit_field, and do not survive to get here. */ + if (XEXP (x, 0) == var + || (GET_CODE (XEXP (x, 0)) == SUBREG + && SUBREG_REG (XEXP (x, 0)) == var)) + { + /* Get TEM as a valid MEM in the mode presently in the insn. - case REG: - new = instantiate_new_reg (x, &offset); - if (new == NULL) - continue; - if (offset == 0) - x = new; + We don't worry about the possibility of MATCH_DUP here; it + is highly unlikely and would be tricky to handle. */ + + tem = XEXP (x, 0); + if (GET_CODE (tem) == SUBREG) + { + if (GET_MODE_BITSIZE (GET_MODE (tem)) + > GET_MODE_BITSIZE (GET_MODE (var))) + { + replacement = find_fixup_replacement (replacements, var); + if (replacement->new == 0) + replacement->new = gen_reg_rtx (GET_MODE (var)); + SUBREG_REG (tem) = replacement->new; + + /* The following code works only if we have a MEM, so we + need to handle the subreg here. We directly substitute + it assuming that a subreg must be OK here. We already + scheduled a replacement to copy the mem into the + subreg. */ + XEXP (x, 0) = tem; + return; + } + else + tem = fixup_memory_subreg (tem, insn, promoted_mode, 0); + } else + tem = fixup_stack_1 (tem, insn); + + /* Unless we want to load from memory, get TEM into the proper mode + for an extract from memory. This can only be done if the + extract is at a constant position and length. */ + + if (! flag_force_mem && GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (x, 2)) == CONST_INT + && ! mode_dependent_address_p (XEXP (tem, 0)) + && ! MEM_VOLATILE_P (tem)) { - start_sequence (); + enum machine_mode wanted_mode = VOIDmode; + enum machine_mode is_mode = GET_MODE (tem); + HOST_WIDE_INT pos = INTVAL (XEXP (x, 2)); - /* Careful, special mode predicates may have stuff in - insn_data[insn_code].operand[i].mode that isn't useful - to us for computing a new value. */ - /* ??? Recognize address_operand and/or "p" constraints - to see if (plus new offset) is a valid before we put - this through expand_simple_binop. */ - x = expand_simple_binop (GET_MODE (x), PLUS, new, - GEN_INT (offset), NULL_RTX, - 1, OPTAB_LIB_WIDEN); - seq = get_insns (); - end_sequence (); - emit_insn_before (seq, insn); + if (GET_CODE (x) == ZERO_EXTRACT) + { + enum machine_mode new_mode + = mode_for_extraction (EP_extzv, 1); + if (new_mode != MAX_MACHINE_MODE) + wanted_mode = new_mode; + } + else if (GET_CODE (x) == SIGN_EXTRACT) + { + enum machine_mode new_mode + = mode_for_extraction (EP_extv, 1); + if (new_mode != MAX_MACHINE_MODE) + wanted_mode = new_mode; + } + + /* If we have a narrower mode, we can do something. */ + if (wanted_mode != VOIDmode + && GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode)) + { + HOST_WIDE_INT offset = pos / BITS_PER_UNIT; + rtx old_pos = XEXP (x, 2); + rtx newmem; + + /* If the bytes and bits are counted differently, we + must adjust the offset. */ + if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN) + offset = (GET_MODE_SIZE (is_mode) + - GET_MODE_SIZE (wanted_mode) - offset); + + pos %= GET_MODE_BITSIZE (wanted_mode); + + newmem = adjust_address_nv (tem, wanted_mode, offset); + + /* Make the change and see if the insn remains valid. */ + INSN_CODE (insn) = -1; + XEXP (x, 0) = newmem; + XEXP (x, 2) = GEN_INT (pos); + + if (recog_memoized (insn) >= 0) + return; + + /* Otherwise, restore old position. XEXP (x, 0) will be + restored later. */ + XEXP (x, 2) = old_pos; + } } - break; - case SUBREG: - new = instantiate_new_reg (SUBREG_REG (x), &offset); - if (new == NULL) - continue; - if (offset != 0) + /* If we get here, the bitfield extract insn can't accept a memory + reference. Copy the input into a register. */ + + tem1 = gen_reg_rtx (GET_MODE (tem)); + emit_insn_before (gen_move_insn (tem1, tem), insn); + XEXP (x, 0) = tem1; + return; + } + break; + + case SUBREG: + if (SUBREG_REG (x) == var) + { + /* If this is a special SUBREG made because VAR was promoted + from a wider mode, replace it with VAR and call ourself + recursively, this time saying that the object previously + had its current mode (by virtue of the SUBREG). */ + + if (SUBREG_PROMOTED_VAR_P (x)) { - start_sequence (); - new = expand_simple_binop (GET_MODE (new), PLUS, new, - GEN_INT (offset), NULL_RTX, - 1, OPTAB_LIB_WIDEN); - seq = get_insns (); - end_sequence (); - emit_insn_before (seq, insn); + *loc = var; + fixup_var_refs_1 (var, GET_MODE (var), loc, insn, replacements, + no_share); + return; } - x = simplify_gen_subreg (recog_data.operand_mode[i], new, - GET_MODE (new), SUBREG_BYTE (x)); - break; - default: - continue; + /* If this SUBREG makes VAR wider, it has become a paradoxical + SUBREG with VAR in memory, but these aren't allowed at this + stage of the compilation. So load VAR into a pseudo and take + a SUBREG of that pseudo. */ + if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (var))) + { + replacement = find_fixup_replacement (replacements, var); + if (replacement->new == 0) + replacement->new = gen_reg_rtx (promoted_mode); + SUBREG_REG (x) = replacement->new; + return; + } + + /* See if we have already found a replacement for this SUBREG. + If so, use it. Otherwise, make a MEM and see if the insn + is recognized. If not, or if we should force MEM into a register, + make a pseudo for this SUBREG. */ + replacement = find_fixup_replacement (replacements, x); + if (replacement->new) + { + enum machine_mode mode = GET_MODE (x); + *loc = replacement->new; + + /* Careful! We may have just replaced a SUBREG by a MEM, which + means that the insn may have become invalid again. We can't + in this case make a new replacement since we already have one + and we must deal with MATCH_DUPs. */ + if (GET_CODE (replacement->new) == MEM) + { + INSN_CODE (insn) = -1; + if (recog_memoized (insn) >= 0) + return; + + fixup_var_refs_1 (replacement->new, mode, &PATTERN (insn), + insn, replacements, no_share); + } + + return; + } + + replacement->new = *loc = fixup_memory_subreg (x, insn, + promoted_mode, 0); + + INSN_CODE (insn) = -1; + if (! flag_force_mem && recog_memoized (insn) >= 0) + return; + + *loc = replacement->new = gen_reg_rtx (GET_MODE (x)); + return; + } + break; + + case SET: + /* First do special simplification of bit-field references. */ + if (GET_CODE (SET_DEST (x)) == SIGN_EXTRACT + || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT) + optimize_bit_field (x, insn, 0); + if (GET_CODE (SET_SRC (x)) == SIGN_EXTRACT + || GET_CODE (SET_SRC (x)) == ZERO_EXTRACT) + optimize_bit_field (x, insn, 0); + + /* For a paradoxical SUBREG inside a ZERO_EXTRACT, load the object + into a register and then store it back out. */ + if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT + && GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG + && SUBREG_REG (XEXP (SET_DEST (x), 0)) == var + && (GET_MODE_SIZE (GET_MODE (XEXP (SET_DEST (x), 0))) + > GET_MODE_SIZE (GET_MODE (var)))) + { + replacement = find_fixup_replacement (replacements, var); + if (replacement->new == 0) + replacement->new = gen_reg_rtx (GET_MODE (var)); + + SUBREG_REG (XEXP (SET_DEST (x), 0)) = replacement->new; + emit_insn_after (gen_move_insn (var, replacement->new), insn); } - /* At this point, X contains the new value for the operand. - Validate the new value vs the insn predicate. Note that - asm insns will have insn_code -1 here. */ - if (!safe_insn_predicate (insn_code, i, x)) + /* If SET_DEST is now a paradoxical SUBREG, put the result of this + insn into a pseudo and store the low part of the pseudo into VAR. */ + if (GET_CODE (SET_DEST (x)) == SUBREG + && SUBREG_REG (SET_DEST (x)) == var + && (GET_MODE_SIZE (GET_MODE (SET_DEST (x))) + > GET_MODE_SIZE (GET_MODE (var)))) { - start_sequence (); - x = force_reg (insn_data[insn_code].operand[i].mode, x); - seq = get_insns (); - end_sequence (); - if (seq) - emit_insn_before (seq, insn); + SET_DEST (x) = tem = gen_reg_rtx (GET_MODE (SET_DEST (x))); + emit_insn_after (gen_move_insn (var, gen_lowpart (GET_MODE (var), + tem)), + insn); + break; } - *recog_data.operand_loc[i] = recog_data.operand[i] = x; - any_change = true; - } + { + rtx dest = SET_DEST (x); + rtx src = SET_SRC (x); + rtx outerdest = dest; - if (any_change) - { - /* Propagate operand changes into the duplicates. */ - for (i = 0; i < recog_data.n_dups; ++i) - *recog_data.dup_loc[i] - = recog_data.operand[(unsigned)recog_data.dup_num[i]]; + while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART + || GET_CODE (dest) == SIGN_EXTRACT + || GET_CODE (dest) == ZERO_EXTRACT) + dest = XEXP (dest, 0); + + if (GET_CODE (src) == SUBREG) + src = SUBREG_REG (src); + + /* If VAR does not appear at the top level of the SET + just scan the lower levels of the tree. */ + + if (src != var && dest != var) + break; - /* Force re-recognition of the instruction for validation. */ - INSN_CODE (insn) = -1; + /* We will need to rerecognize this insn. */ + INSN_CODE (insn) = -1; + + if (GET_CODE (outerdest) == ZERO_EXTRACT && dest == var + && mode_for_extraction (EP_insv, -1) != MAX_MACHINE_MODE) + { + /* Since this case will return, ensure we fixup all the + operands here. */ + fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 1), + insn, replacements, no_share); + fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 2), + insn, replacements, no_share); + fixup_var_refs_1 (var, promoted_mode, &SET_SRC (x), + insn, replacements, no_share); + + tem = XEXP (outerdest, 0); + + /* Clean up (SUBREG:SI (MEM:mode ...) 0) + that may appear inside a ZERO_EXTRACT. + This was legitimate when the MEM was a REG. */ + if (GET_CODE (tem) == SUBREG + && SUBREG_REG (tem) == var) + tem = fixup_memory_subreg (tem, insn, promoted_mode, 0); + else + tem = fixup_stack_1 (tem, insn); + + if (GET_CODE (XEXP (outerdest, 1)) == CONST_INT + && GET_CODE (XEXP (outerdest, 2)) == CONST_INT + && ! mode_dependent_address_p (XEXP (tem, 0)) + && ! MEM_VOLATILE_P (tem)) + { + enum machine_mode wanted_mode; + enum machine_mode is_mode = GET_MODE (tem); + HOST_WIDE_INT pos = INTVAL (XEXP (outerdest, 2)); + + wanted_mode = mode_for_extraction (EP_insv, 0); + + /* If we have a narrower mode, we can do something. */ + if (GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode)) + { + HOST_WIDE_INT offset = pos / BITS_PER_UNIT; + rtx old_pos = XEXP (outerdest, 2); + rtx newmem; + + if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN) + offset = (GET_MODE_SIZE (is_mode) + - GET_MODE_SIZE (wanted_mode) - offset); + + pos %= GET_MODE_BITSIZE (wanted_mode); + + newmem = adjust_address_nv (tem, wanted_mode, offset); + + /* Make the change and see if the insn remains valid. */ + INSN_CODE (insn) = -1; + XEXP (outerdest, 0) = newmem; + XEXP (outerdest, 2) = GEN_INT (pos); + + if (recog_memoized (insn) >= 0) + return; + + /* Otherwise, restore old position. XEXP (x, 0) will be + restored later. */ + XEXP (outerdest, 2) = old_pos; + } + } + + /* If we get here, the bit-field store doesn't allow memory + or isn't located at a constant position. Load the value into + a register, do the store, and put it back into memory. */ + + tem1 = gen_reg_rtx (GET_MODE (tem)); + emit_insn_before (gen_move_insn (tem1, tem), insn); + emit_insn_after (gen_move_insn (tem, tem1), insn); + XEXP (outerdest, 0) = tem1; + return; + } + + /* STRICT_LOW_PART is a no-op on memory references + and it can cause combinations to be unrecognizable, + so eliminate it. */ + + if (dest == var && GET_CODE (SET_DEST (x)) == STRICT_LOW_PART) + SET_DEST (x) = XEXP (SET_DEST (x), 0); + + /* A valid insn to copy VAR into or out of a register + must be left alone, to avoid an infinite loop here. + If the reference to VAR is by a subreg, fix that up, + since SUBREG is not valid for a memref. + Also fix up the address of the stack slot. + + Note that we must not try to recognize the insn until + after we know that we have valid addresses and no + (subreg (mem ...) ...) constructs, since these interfere + with determining the validity of the insn. */ + + if ((SET_SRC (x) == var + || (GET_CODE (SET_SRC (x)) == SUBREG + && SUBREG_REG (SET_SRC (x)) == var)) + && (GET_CODE (SET_DEST (x)) == REG + || (GET_CODE (SET_DEST (x)) == SUBREG + && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG)) + && GET_MODE (var) == promoted_mode + && x == single_set (insn)) + { + rtx pat, last; + + if (GET_CODE (SET_SRC (x)) == SUBREG + && (GET_MODE_SIZE (GET_MODE (SET_SRC (x))) + > GET_MODE_SIZE (GET_MODE (var)))) + { + /* This (subreg VAR) is now a paradoxical subreg. We need + to replace VAR instead of the subreg. */ + replacement = find_fixup_replacement (replacements, var); + if (replacement->new == NULL_RTX) + replacement->new = gen_reg_rtx (GET_MODE (var)); + SUBREG_REG (SET_SRC (x)) = replacement->new; + } + else + { + replacement = find_fixup_replacement (replacements, SET_SRC (x)); + if (replacement->new) + SET_SRC (x) = replacement->new; + else if (GET_CODE (SET_SRC (x)) == SUBREG) + SET_SRC (x) = replacement->new + = fixup_memory_subreg (SET_SRC (x), insn, promoted_mode, + 0); + else + SET_SRC (x) = replacement->new + = fixup_stack_1 (SET_SRC (x), insn); + } + + if (recog_memoized (insn) >= 0) + return; + + /* INSN is not valid, but we know that we want to + copy SET_SRC (x) to SET_DEST (x) in some way. So + we generate the move and see whether it requires more + than one insn. If it does, we emit those insns and + delete INSN. Otherwise, we can just replace the pattern + of INSN; we have already verified above that INSN has + no other function that to do X. */ + + pat = gen_move_insn (SET_DEST (x), SET_SRC (x)); + if (NEXT_INSN (pat) != NULL_RTX) + { + last = emit_insn_before (pat, insn); + + /* INSN might have REG_RETVAL or other important notes, so + we need to store the pattern of the last insn in the + sequence into INSN similarly to the normal case. LAST + should not have REG_NOTES, but we allow them if INSN has + no REG_NOTES. */ + if (REG_NOTES (last) && REG_NOTES (insn)) + abort (); + if (REG_NOTES (last)) + REG_NOTES (insn) = REG_NOTES (last); + PATTERN (insn) = PATTERN (last); + + delete_insn (last); + } + else + PATTERN (insn) = PATTERN (pat); + + return; + } + + if ((SET_DEST (x) == var + || (GET_CODE (SET_DEST (x)) == SUBREG + && SUBREG_REG (SET_DEST (x)) == var)) + && (GET_CODE (SET_SRC (x)) == REG + || (GET_CODE (SET_SRC (x)) == SUBREG + && GET_CODE (SUBREG_REG (SET_SRC (x))) == REG)) + && GET_MODE (var) == promoted_mode + && x == single_set (insn)) + { + rtx pat, last; + + if (GET_CODE (SET_DEST (x)) == SUBREG) + SET_DEST (x) = fixup_memory_subreg (SET_DEST (x), insn, + promoted_mode, 0); + else + SET_DEST (x) = fixup_stack_1 (SET_DEST (x), insn); + + if (recog_memoized (insn) >= 0) + return; + + pat = gen_move_insn (SET_DEST (x), SET_SRC (x)); + if (NEXT_INSN (pat) != NULL_RTX) + { + last = emit_insn_before (pat, insn); + + /* INSN might have REG_RETVAL or other important notes, so + we need to store the pattern of the last insn in the + sequence into INSN similarly to the normal case. LAST + should not have REG_NOTES, but we allow them if INSN has + no REG_NOTES. */ + if (REG_NOTES (last) && REG_NOTES (insn)) + abort (); + if (REG_NOTES (last)) + REG_NOTES (insn) = REG_NOTES (last); + PATTERN (insn) = PATTERN (last); + + delete_insn (last); + } + else + PATTERN (insn) = PATTERN (pat); + + return; + } + + /* Otherwise, storing into VAR must be handled specially + by storing into a temporary and copying that into VAR + with a new insn after this one. Note that this case + will be used when storing into a promoted scalar since + the insn will now have different modes on the input + and output and hence will be invalid (except for the case + of setting it to a constant, which does not need any + change if it is valid). We generate extra code in that case, + but combine.c will eliminate it. */ + + if (dest == var) + { + rtx temp; + rtx fixeddest = SET_DEST (x); + enum machine_mode temp_mode; + + /* STRICT_LOW_PART can be discarded, around a MEM. */ + if (GET_CODE (fixeddest) == STRICT_LOW_PART) + fixeddest = XEXP (fixeddest, 0); + /* Convert (SUBREG (MEM)) to a MEM in a changed mode. */ + if (GET_CODE (fixeddest) == SUBREG) + { + fixeddest = fixup_memory_subreg (fixeddest, insn, + promoted_mode, 0); + temp_mode = GET_MODE (fixeddest); + } + else + { + fixeddest = fixup_stack_1 (fixeddest, insn); + temp_mode = promoted_mode; + } + + temp = gen_reg_rtx (temp_mode); + + emit_insn_after (gen_move_insn (fixeddest, + gen_lowpart (GET_MODE (fixeddest), + temp)), + insn); + + SET_DEST (x) = temp; + } + } + + default: + break; } - if (asm_noperands (PATTERN (insn)) >= 0) + /* Nothing special about this RTX; fix its operands. */ + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { - if (!check_asm_operands (PATTERN (insn))) + if (fmt[i] == 'e') + fixup_var_refs_1 (var, promoted_mode, &XEXP (x, i), insn, replacements, + no_share); + else if (fmt[i] == 'E') { - error_for_asm (insn, "impossible constraint in %<asm%>"); - delete_insn (insn); + int j; + for (j = 0; j < XVECLEN (x, i); j++) + fixup_var_refs_1 (var, promoted_mode, &XVECEXP (x, i, j), + insn, replacements, no_share); } } - else - { - if (recog_memoized (insn) < 0) - fatal_insn_not_found (insn); - } } + +/* Previously, X had the form (SUBREG:m1 (REG:PROMOTED_MODE ...)). + The REG was placed on the stack, so X now has the form (SUBREG:m1 + (MEM:m2 ...)). -/* Subroutine of instantiate_decls. Given RTL representing a decl, - do any instantiation required. */ + Return an rtx (MEM:m1 newaddr) which is equivalent. If any insns + must be emitted to compute NEWADDR, put them before INSN. -static void -instantiate_decl (rtx x) + UNCRITICAL nonzero means accept paradoxical subregs. + This is used for subregs found inside REG_NOTES. */ + +static rtx +fixup_memory_subreg (rtx x, rtx insn, enum machine_mode promoted_mode, int uncritical) { - rtx addr; + int offset; + rtx mem = SUBREG_REG (x); + rtx addr = XEXP (mem, 0); + enum machine_mode mode = GET_MODE (x); + rtx result, seq; + + /* Paradoxical SUBREGs are usually invalid during RTL generation. */ + if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (mem)) && ! uncritical) + abort (); + + offset = SUBREG_BYTE (x); + if (BYTES_BIG_ENDIAN) + /* If the PROMOTED_MODE is wider than the mode of the MEM, adjust + the offset so that it points to the right location within the + MEM. */ + offset -= (GET_MODE_SIZE (promoted_mode) - GET_MODE_SIZE (GET_MODE (mem))); + + if (!flag_force_addr + && memory_address_p (mode, plus_constant (addr, offset))) + /* Shortcut if no insns need be emitted. */ + return adjust_address (mem, mode, offset); - if (x == 0) - return; + start_sequence (); + result = adjust_address (mem, mode, offset); + seq = get_insns (); + end_sequence (); - /* If this is a CONCAT, recurse for the pieces. */ - if (GET_CODE (x) == CONCAT) - { - instantiate_decl (XEXP (x, 0)); - instantiate_decl (XEXP (x, 1)); - return; - } + emit_insn_before (seq, insn); + return result; +} - /* If this is not a MEM, no need to do anything. Similarly if the - address is a constant or a register that is not a virtual register. */ - if (!MEM_P (x)) - return; +/* Do fixup_memory_subreg on all (SUBREG (MEM ...) ...) contained in X. + Replace subexpressions of X in place. + If X itself is a (SUBREG (MEM ...) ...), return the replacement expression. + Otherwise return X, with its contents possibly altered. - addr = XEXP (x, 0); - if (CONSTANT_P (addr) - || (REG_P (addr) - && (REGNO (addr) < FIRST_VIRTUAL_REGISTER - || REGNO (addr) > LAST_VIRTUAL_REGISTER))) - return; + INSN, PROMOTED_MODE and UNCRITICAL are as for + fixup_memory_subreg. */ - for_each_rtx (&XEXP (x, 0), instantiate_virtual_regs_in_rtx, NULL); -} +static rtx +walk_fixup_memory_subreg (rtx x, rtx insn, enum machine_mode promoted_mode, + int uncritical) +{ + enum rtx_code code; + const char *fmt; + int i; -/* Helper for instantiate_decls called via walk_tree: Process all decls - in the given DECL_VALUE_EXPR. */ + if (x == 0) + return 0; -static tree -instantiate_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) -{ - tree t = *tp; - if (! EXPR_P (t)) + code = GET_CODE (x); + + if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM) + return fixup_memory_subreg (x, insn, promoted_mode, uncritical); + + /* Nothing special about this RTX; fix its operands. */ + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { - *walk_subtrees = 0; - if (DECL_P (t) && DECL_RTL_SET_P (t)) - instantiate_decl (DECL_RTL (t)); + if (fmt[i] == 'e') + XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn, + promoted_mode, uncritical); + else if (fmt[i] == 'E') + { + int j; + for (j = 0; j < XVECLEN (x, i); j++) + XVECEXP (x, i, j) + = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn, + promoted_mode, uncritical); + } } - return NULL; + return x; } + +/* For each memory ref within X, if it refers to a stack slot + with an out of range displacement, put the address in a temp register + (emitting new insns before INSN to load these registers) + and alter the memory ref to use that register. + Replace each such MEM rtx with a copy, to avoid clobberage. */ -/* Subroutine of instantiate_decls: Process all decls in the given - BLOCK node and all its subblocks. */ - -static void -instantiate_decls_1 (tree let) +static rtx +fixup_stack_1 (rtx x, rtx insn) { - tree t; + int i; + RTX_CODE code = GET_CODE (x); + const char *fmt; - for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) + if (code == MEM) { - if (DECL_RTL_SET_P (t)) - instantiate_decl (DECL_RTL (t)); - if (TREE_CODE (t) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (t)) + rtx ad = XEXP (x, 0); + /* If we have address of a stack slot but it's not valid + (displacement is too large), compute the sum in a register. */ + if (GET_CODE (ad) == PLUS + && GET_CODE (XEXP (ad, 0)) == REG + && ((REGNO (XEXP (ad, 0)) >= FIRST_VIRTUAL_REGISTER + && REGNO (XEXP (ad, 0)) <= LAST_VIRTUAL_REGISTER) + || REGNO (XEXP (ad, 0)) == FRAME_POINTER_REGNUM +#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + || REGNO (XEXP (ad, 0)) == HARD_FRAME_POINTER_REGNUM +#endif + || REGNO (XEXP (ad, 0)) == STACK_POINTER_REGNUM + || REGNO (XEXP (ad, 0)) == ARG_POINTER_REGNUM + || XEXP (ad, 0) == current_function_internal_arg_pointer) + && GET_CODE (XEXP (ad, 1)) == CONST_INT) { - tree v = DECL_VALUE_EXPR (t); - walk_tree (&v, instantiate_expr, NULL, NULL); + rtx temp, seq; + if (memory_address_p (GET_MODE (x), ad)) + return x; + + start_sequence (); + temp = copy_to_reg (ad); + seq = get_insns (); + end_sequence (); + emit_insn_before (seq, insn); + return replace_equiv_address (x, temp); } + return x; } - /* Process all subblocks. */ - for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t)) - instantiate_decls_1 (t); + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + XEXP (x, i) = fixup_stack_1 (XEXP (x, i), insn); + else if (fmt[i] == 'E') + { + int j; + for (j = 0; j < XVECLEN (x, i); j++) + XVECEXP (x, i, j) = fixup_stack_1 (XVECEXP (x, i, j), insn); + } + } + return x; } + +/* Optimization: a bit-field instruction whose field + happens to be a byte or halfword in memory + can be changed to a move instruction. -/* Scan all decls in FNDECL (both variables and parameters) and instantiate - all virtual registers in their DECL_RTL's. */ + We call here when INSN is an insn to examine or store into a bit-field. + BODY is the SET-rtx to be altered. + + EQUIV_MEM is the table `reg_equiv_mem' if that is available; else 0. + (Currently this is called only from function.c, and EQUIV_MEM + is always 0.) */ static void -instantiate_decls (tree fndecl) +optimize_bit_field (rtx body, rtx insn, rtx *equiv_mem) { - tree decl; + rtx bitfield; + int destflag; + rtx seq = 0; + enum machine_mode mode; - /* Process all parameters of the function. */ - for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl)) + if (GET_CODE (SET_DEST (body)) == SIGN_EXTRACT + || GET_CODE (SET_DEST (body)) == ZERO_EXTRACT) + bitfield = SET_DEST (body), destflag = 1; + else + bitfield = SET_SRC (body), destflag = 0; + + /* First check that the field being stored has constant size and position + and is in fact a byte or halfword suitably aligned. */ + + if (GET_CODE (XEXP (bitfield, 1)) == CONST_INT + && GET_CODE (XEXP (bitfield, 2)) == CONST_INT + && ((mode = mode_for_size (INTVAL (XEXP (bitfield, 1)), MODE_INT, 1)) + != BLKmode) + && INTVAL (XEXP (bitfield, 2)) % INTVAL (XEXP (bitfield, 1)) == 0) { - instantiate_decl (DECL_RTL (decl)); - instantiate_decl (DECL_INCOMING_RTL (decl)); - if (DECL_HAS_VALUE_EXPR_P (decl)) + rtx memref = 0; + + /* Now check that the containing word is memory, not a register, + and that it is safe to change the machine mode. */ + + if (GET_CODE (XEXP (bitfield, 0)) == MEM) + memref = XEXP (bitfield, 0); + else if (GET_CODE (XEXP (bitfield, 0)) == REG + && equiv_mem != 0) + memref = equiv_mem[REGNO (XEXP (bitfield, 0))]; + else if (GET_CODE (XEXP (bitfield, 0)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (bitfield, 0))) == MEM) + memref = SUBREG_REG (XEXP (bitfield, 0)); + else if (GET_CODE (XEXP (bitfield, 0)) == SUBREG + && equiv_mem != 0 + && GET_CODE (SUBREG_REG (XEXP (bitfield, 0))) == REG) + memref = equiv_mem[REGNO (SUBREG_REG (XEXP (bitfield, 0)))]; + + if (memref + && ! mode_dependent_address_p (XEXP (memref, 0)) + && ! MEM_VOLATILE_P (memref)) { - tree v = DECL_VALUE_EXPR (decl); - walk_tree (&v, instantiate_expr, NULL, NULL); - } - } + /* Now adjust the address, first for any subreg'ing + that we are now getting rid of, + and then for which byte of the word is wanted. */ - /* Now process all variables defined in the function or its subblocks. */ - instantiate_decls_1 (DECL_INITIAL (fndecl)); -} + HOST_WIDE_INT offset = INTVAL (XEXP (bitfield, 2)); + rtx insns; -/* Pass through the INSNS of function FNDECL and convert virtual register - references to hard register references. */ + /* Adjust OFFSET to count bits from low-address byte. */ + if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN) + offset = (GET_MODE_BITSIZE (GET_MODE (XEXP (bitfield, 0))) + - offset - INTVAL (XEXP (bitfield, 1))); -static unsigned int -instantiate_virtual_regs (void) -{ - rtx insn; + /* Adjust OFFSET to count bytes from low-address byte. */ + offset /= BITS_PER_UNIT; + if (GET_CODE (XEXP (bitfield, 0)) == SUBREG) + { + offset += (SUBREG_BYTE (XEXP (bitfield, 0)) + / UNITS_PER_WORD) * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset -= (MIN (UNITS_PER_WORD, + GET_MODE_SIZE (GET_MODE (XEXP (bitfield, 0)))) + - MIN (UNITS_PER_WORD, + GET_MODE_SIZE (GET_MODE (memref)))); + } - /* Compute the offsets to use for this function. */ - in_arg_offset = FIRST_PARM_OFFSET (current_function_decl); - var_offset = STARTING_FRAME_OFFSET; - dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl); - out_arg_offset = STACK_POINTER_OFFSET; -#ifdef FRAME_POINTER_CFA_OFFSET - cfa_offset = FRAME_POINTER_CFA_OFFSET (current_function_decl); -#else - cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl); -#endif + start_sequence (); + memref = adjust_address (memref, mode, offset); + insns = get_insns (); + end_sequence (); + emit_insn_before (insns, insn); - /* Initialize recognition, indicating that volatile is OK. */ - init_recog (); + /* Store this memory reference where + we found the bit field reference. */ - /* Scan through all the insns, instantiating every virtual register still - present. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - { - /* These patterns in the instruction stream can never be recognized. - Fortunately, they shouldn't contain virtual registers either. */ - if (GET_CODE (PATTERN (insn)) == USE - || GET_CODE (PATTERN (insn)) == CLOBBER - || GET_CODE (PATTERN (insn)) == ADDR_VEC - || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC - || GET_CODE (PATTERN (insn)) == ASM_INPUT) - continue; + if (destflag) + { + validate_change (insn, &SET_DEST (body), memref, 1); + if (! CONSTANT_ADDRESS_P (SET_SRC (body))) + { + rtx src = SET_SRC (body); + while (GET_CODE (src) == SUBREG + && SUBREG_BYTE (src) == 0) + src = SUBREG_REG (src); + if (GET_MODE (src) != GET_MODE (memref)) + src = gen_lowpart (GET_MODE (memref), SET_SRC (body)); + validate_change (insn, &SET_SRC (body), src, 1); + } + else if (GET_MODE (SET_SRC (body)) != VOIDmode + && GET_MODE (SET_SRC (body)) != GET_MODE (memref)) + /* This shouldn't happen because anything that didn't have + one of these modes should have got converted explicitly + and then referenced through a subreg. + This is so because the original bit-field was + handled by agg_mode and so its tree structure had + the same mode that memref now has. */ + abort (); + } + else + { + rtx dest = SET_DEST (body); - instantiate_virtual_regs_in_insn (insn); + while (GET_CODE (dest) == SUBREG + && SUBREG_BYTE (dest) == 0 + && (GET_MODE_CLASS (GET_MODE (dest)) + == GET_MODE_CLASS (GET_MODE (SUBREG_REG (dest)))) + && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) + <= UNITS_PER_WORD)) + dest = SUBREG_REG (dest); - if (INSN_DELETED_P (insn)) - continue; + validate_change (insn, &SET_DEST (body), dest, 1); - for_each_rtx (®_NOTES (insn), instantiate_virtual_regs_in_rtx, NULL); + if (GET_MODE (dest) == GET_MODE (memref)) + validate_change (insn, &SET_SRC (body), memref, 1); + else + { + /* Convert the mem ref to the destination mode. */ + rtx newreg = gen_reg_rtx (GET_MODE (dest)); - /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE. */ - if (GET_CODE (insn) == CALL_INSN) - for_each_rtx (&CALL_INSN_FUNCTION_USAGE (insn), - instantiate_virtual_regs_in_rtx, NULL); - } + start_sequence (); + convert_move (newreg, memref, + GET_CODE (SET_SRC (body)) == ZERO_EXTRACT); + seq = get_insns (); + end_sequence (); - /* Instantiate the virtual registers in the DECLs for debugging purposes. */ - instantiate_decls (current_function_decl); + validate_change (insn, &SET_SRC (body), newreg, 1); + } + } - /* Indicate that, from now on, assign_stack_local should use - frame_pointer_rtx. */ - virtuals_instantiated = 1; - return 0; -} + /* See if we can convert this extraction or insertion into + a simple move insn. We might not be able to do so if this + was, for example, part of a PARALLEL. -struct tree_opt_pass pass_instantiate_virtual_regs = -{ - "vregs", /* name */ - NULL, /* gate */ - instantiate_virtual_regs, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - 0, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ -}; + If we succeed, write out any needed conversions. If we fail, + it is hard to guess why we failed, so don't do anything + special; just let the optimization be suppressed. */ + if (apply_change_group () && seq) + emit_insn_before (seq, insn); + } + } +} -/* Return 1 if EXP is an aggregate type (or a value with aggregate type). - This means a type for which function calls must pass an address to the - function or get an address back from the function. - EXP may be a type node or an expression (whose type is tested). */ +/* These routines are responsible for converting virtual register references + to the actual hard register references once RTL generation is complete. -int -aggregate_value_p (tree exp, tree fntype) -{ - int i, regno, nregs; - rtx reg; + The following four variables are used for communication between the + routines. They contain the offsets of the virtual registers from their + respective hard registers. */ - tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp); +static int in_arg_offset; +static int var_offset; +static int dynamic_offset; +static int out_arg_offset; +static int cfa_offset; - /* DECL node associated with FNTYPE when relevant, which we might need to - check for by-invisible-reference returns, typically for CALL_EXPR input - EXPressions. */ - tree fndecl = NULL_TREE; - - if (fntype) - switch (TREE_CODE (fntype)) - { - case CALL_EXPR: - fndecl = get_callee_fndecl (fntype); - fntype = fndecl ? TREE_TYPE (fndecl) : 0; - break; - case FUNCTION_DECL: - fndecl = fntype; - fntype = TREE_TYPE (fndecl); - break; - case FUNCTION_TYPE: - case METHOD_TYPE: - break; - case IDENTIFIER_NODE: - fntype = 0; - break; - default: - /* We don't expect other rtl types here. */ - gcc_unreachable (); - } +/* In most machines, the stack pointer register is equivalent to the bottom + of the stack. */ - if (TREE_CODE (type) == VOID_TYPE) - return 0; +#ifndef STACK_POINTER_OFFSET +#define STACK_POINTER_OFFSET 0 +#endif - /* If the front end has decided that this needs to be passed by - reference, do so. */ - if ((TREE_CODE (exp) == PARM_DECL || TREE_CODE (exp) == RESULT_DECL) - && DECL_BY_REFERENCE (exp)) - return 1; +/* If not defined, pick an appropriate default for the offset of dynamically + allocated memory depending on the value of ACCUMULATE_OUTGOING_ARGS, + REG_PARM_STACK_SPACE, and OUTGOING_REG_PARM_STACK_SPACE. */ - /* If the EXPression is a CALL_EXPR, honor DECL_BY_REFERENCE set on the - called function RESULT_DECL, meaning the function returns in memory by - invisible reference. This check lets front-ends not set TREE_ADDRESSABLE - on the function type, which used to be the way to request such a return - mechanism but might now be causing troubles at gimplification time if - temporaries with the function type need to be created. */ - if (TREE_CODE (exp) == CALL_EXPR && fndecl && DECL_RESULT (fndecl) - && DECL_BY_REFERENCE (DECL_RESULT (fndecl))) - return 1; - - if (targetm.calls.return_in_memory (type, fntype)) - return 1; - /* Types that are TREE_ADDRESSABLE must be constructed in memory, - and thus can't be returned in registers. */ - if (TREE_ADDRESSABLE (type)) - return 1; - if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type)) - return 1; - /* Make sure we have suitable call-clobbered regs to return - the value in; if not, we must return it in memory. */ - reg = hard_function_value (type, 0, fntype, 0); +#ifndef STACK_DYNAMIC_OFFSET - /* If we have something other than a REG (e.g. a PARALLEL), then assume - it is OK. */ - if (!REG_P (reg)) - return 0; +/* The bottom of the stack points to the actual arguments. If + REG_PARM_STACK_SPACE is defined, this includes the space for the register + parameters. However, if OUTGOING_REG_PARM_STACK space is not defined, + stack space for register parameters is not pushed by the caller, but + rather part of the fixed stack areas and hence not included in + `current_function_outgoing_args_size'. Nevertheless, we must allow + for it when allocating stack dynamic objects. */ - regno = REGNO (reg); - nregs = hard_regno_nregs[regno][TYPE_MODE (type)]; - for (i = 0; i < nregs; i++) - if (! call_used_regs[regno + i]) - return 1; - return 0; -} - -/* Return true if we should assign DECL a pseudo register; false if it - should live on the local stack. */ +#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE) +#define STACK_DYNAMIC_OFFSET(FNDECL) \ +((ACCUMULATE_OUTGOING_ARGS \ + ? (current_function_outgoing_args_size + REG_PARM_STACK_SPACE (FNDECL)) : 0)\ + + (STACK_POINTER_OFFSET)) \ -bool -use_register_for_decl (tree decl) -{ - /* Honor volatile. */ - if (TREE_SIDE_EFFECTS (decl)) - return false; - - /* Honor addressability. */ - if (TREE_ADDRESSABLE (decl)) - return false; - - /* Only register-like things go in registers. */ - if (DECL_MODE (decl) == BLKmode) - return false; - - /* If -ffloat-store specified, don't put explicit float variables - into registers. */ - /* ??? This should be checked after DECL_ARTIFICIAL, but tree-ssa - propagates values across these stores, and it probably shouldn't. */ - if (flag_float_store && FLOAT_TYPE_P (TREE_TYPE (decl))) - return false; - - /* If we're not interested in tracking debugging information for - this decl, then we can certainly put it in a register. */ - if (DECL_IGNORED_P (decl)) - return true; +#else +#define STACK_DYNAMIC_OFFSET(FNDECL) \ +((ACCUMULATE_OUTGOING_ARGS ? current_function_outgoing_args_size : 0) \ + + (STACK_POINTER_OFFSET)) +#endif +#endif - return (optimize || DECL_REGISTER (decl)); -} +/* On most machines, the CFA coincides with the first incoming parm. */ + +#ifndef ARG_POINTER_CFA_OFFSET +#define ARG_POINTER_CFA_OFFSET(FNDECL) FIRST_PARM_OFFSET (FNDECL) +#endif -/* Return true if TYPE should be passed by invisible reference. */ +/* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just + had its address taken. DECL is the decl or SAVE_EXPR for the + object stored in the register, for later use if we do need to force + REG into the stack. REG is overwritten by the MEM like in + put_reg_into_stack. RESCAN is true if previously emitted + instructions must be rescanned and modified now that the REG has + been transformed. */ -bool -pass_by_reference (CUMULATIVE_ARGS *ca, enum machine_mode mode, - tree type, bool named_arg) +rtx +gen_mem_addressof (rtx reg, tree decl, int rescan) { - if (type) + rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)), + REGNO (reg), decl); + + /* Calculate this before we start messing with decl's RTL. */ + HOST_WIDE_INT set = decl ? get_alias_set (decl) : 0; + + /* If the original REG was a user-variable, then so is the REG whose + address is being taken. Likewise for unchanging. */ + REG_USERVAR_P (XEXP (r, 0)) = REG_USERVAR_P (reg); + RTX_UNCHANGING_P (XEXP (r, 0)) = RTX_UNCHANGING_P (reg); + + PUT_CODE (reg, MEM); + MEM_ATTRS (reg) = 0; + XEXP (reg, 0) = r; + + if (decl) { - /* If this type contains non-trivial constructors, then it is - forbidden for the middle-end to create any new copies. */ - if (TREE_ADDRESSABLE (type)) - return true; + tree type = TREE_TYPE (decl); + enum machine_mode decl_mode + = (DECL_P (decl) ? DECL_MODE (decl) : TYPE_MODE (TREE_TYPE (decl))); + rtx decl_rtl = (TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl) + : DECL_RTL_IF_SET (decl)); - /* GCC post 3.4 passes *all* variable sized types by reference. */ - if (!TYPE_SIZE (type) || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) - return true; - } + PUT_MODE (reg, decl_mode); - return targetm.calls.pass_by_reference (ca, mode, type, named_arg); -} + /* Clear DECL_RTL momentarily so functions below will work + properly, then set it again. */ + if (DECL_P (decl) && decl_rtl == reg) + SET_DECL_RTL (decl, 0); -/* Return true if TYPE, which is passed by reference, should be callee - copied instead of caller copied. */ + set_mem_attributes (reg, decl, 1); + set_mem_alias_set (reg, set); -bool -reference_callee_copied (CUMULATIVE_ARGS *ca, enum machine_mode mode, - tree type, bool named_arg) -{ - if (type && TREE_ADDRESSABLE (type)) - return false; - return targetm.calls.callee_copies (ca, mode, type, named_arg); -} + if (DECL_P (decl) && decl_rtl == reg) + SET_DECL_RTL (decl, reg); -/* Structures to communicate between the subroutines of assign_parms. - The first holds data persistent across all parameters, the second - is cleared out for each parameter. */ + if (rescan + && (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0))) + fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), reg, 0); + } + else if (rescan) + { + /* This can only happen during reload. Clear the same flag bits as + reload. */ + MEM_VOLATILE_P (reg) = 0; + RTX_UNCHANGING_P (reg) = 0; + MEM_IN_STRUCT_P (reg) = 0; + MEM_SCALAR_P (reg) = 0; + MEM_ATTRS (reg) = 0; + + fixup_var_refs (reg, GET_MODE (reg), 0, reg, 0); + } -struct assign_parm_data_all -{ - CUMULATIVE_ARGS args_so_far; - struct args_size stack_args_size; - tree function_result_decl; - tree orig_fnargs; - rtx conversion_insns; - HOST_WIDE_INT pretend_args_size; - HOST_WIDE_INT extra_pretend_bytes; - int reg_parm_stack_space; -}; + return reg; +} + +/* If DECL has an RTL that is an ADDRESSOF rtx, put it into the stack. */ -struct assign_parm_data_one +void +flush_addressof (tree decl) { - tree nominal_type; - tree passed_type; - rtx entry_parm; - rtx stack_parm; - enum machine_mode nominal_mode; - enum machine_mode passed_mode; - enum machine_mode promoted_mode; - struct locate_and_pad_arg_data locate; - int partial; - BOOL_BITFIELD named_arg : 1; - BOOL_BITFIELD passed_pointer : 1; - BOOL_BITFIELD on_stack : 1; - BOOL_BITFIELD loaded_in_reg : 1; -}; + if ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL) + && DECL_RTL (decl) != 0 + && GET_CODE (DECL_RTL (decl)) == MEM + && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF + && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == REG) + put_addressof_into_stack (XEXP (DECL_RTL (decl), 0), 0); +} -/* A subroutine of assign_parms. Initialize ALL. */ +/* Force the register pointed to by R, an ADDRESSOF rtx, into the stack. */ static void -assign_parms_initialize_all (struct assign_parm_data_all *all) +put_addressof_into_stack (rtx r, htab_t ht) { - tree fntype; + tree decl, type; + bool volatile_p, used_p; - memset (all, 0, sizeof (*all)); + rtx reg = XEXP (r, 0); - fntype = TREE_TYPE (current_function_decl); + if (GET_CODE (reg) != REG) + abort (); -#ifdef INIT_CUMULATIVE_INCOMING_ARGS - INIT_CUMULATIVE_INCOMING_ARGS (all->args_so_far, fntype, NULL_RTX); -#else - INIT_CUMULATIVE_ARGS (all->args_so_far, fntype, NULL_RTX, - current_function_decl, -1); -#endif + decl = ADDRESSOF_DECL (r); + if (decl) + { + type = TREE_TYPE (decl); + volatile_p = (TREE_CODE (decl) != SAVE_EXPR + && TREE_THIS_VOLATILE (decl)); + used_p = (TREE_USED (decl) + || (DECL_P (decl) && DECL_INITIAL (decl) != 0)); + } + else + { + type = NULL_TREE; + volatile_p = false; + used_p = true; + } -#ifdef REG_PARM_STACK_SPACE - all->reg_parm_stack_space = REG_PARM_STACK_SPACE (current_function_decl); -#endif + put_reg_into_stack (0, reg, type, GET_MODE (reg), ADDRESSOF_REGNO (r), + volatile_p, used_p, false, ht); } -/* If ARGS contains entries with complex types, split the entry into two - entries of the component type. Return a new list of substitutions are - needed, else the old list. */ +/* List of replacements made below in purge_addressof_1 when creating + bitfield insertions. */ +static rtx purge_bitfield_addressof_replacements; -static tree -split_complex_args (tree args) +/* List of replacements made below in purge_addressof_1 for patterns + (MEM (ADDRESSOF (REG ...))). The key of the list entry is the + corresponding (ADDRESSOF (REG ...)) and value is a substitution for + the all pattern. List PURGE_BITFIELD_ADDRESSOF_REPLACEMENTS is not + enough in complex cases, e.g. when some field values can be + extracted by usage MEM with narrower mode. */ +static rtx purge_addressof_replacements; + +/* Helper function for purge_addressof. See if the rtx expression at *LOC + in INSN needs to be changed. If FORCE, always put any ADDRESSOFs into + the stack. If the function returns FALSE then the replacement could not + be made. If MAY_POSTPONE is true and we would not put the addressof + to stack, postpone processing of the insn. */ + +static bool +purge_addressof_1 (rtx *loc, rtx insn, int force, int store, int may_postpone, + htab_t ht) { - tree p; + rtx x; + RTX_CODE code; + int i, j; + const char *fmt; + bool result = true; + bool libcall = false; - /* Before allocating memory, check for the common case of no complex. */ - for (p = args; p; p = TREE_CHAIN (p)) + /* Re-start here to avoid recursion in common cases. */ + restart: + + x = *loc; + if (x == 0) + return true; + + /* Is this a libcall? */ + if (!insn) + libcall = REG_NOTE_KIND (*loc) == REG_RETVAL; + + code = GET_CODE (x); + + /* If we don't return in any of the cases below, we will recurse inside + the RTX, which will normally result in any ADDRESSOF being forced into + memory. */ + if (code == SET) { - tree type = TREE_TYPE (p); - if (TREE_CODE (type) == COMPLEX_TYPE - && targetm.calls.split_complex_arg (type)) - goto found; + result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, + may_postpone, ht); + result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, + may_postpone, ht); + return result; } - return args; + else if (code == ADDRESSOF) + { + rtx sub, insns; - found: - args = copy_list (args); + if (GET_CODE (XEXP (x, 0)) != MEM) + put_addressof_into_stack (x, ht); - for (p = args; p; p = TREE_CHAIN (p)) - { - tree type = TREE_TYPE (p); - if (TREE_CODE (type) == COMPLEX_TYPE - && targetm.calls.split_complex_arg (type)) - { - tree decl; - tree subtype = TREE_TYPE (type); - bool addressable = TREE_ADDRESSABLE (p); + /* We must create a copy of the rtx because it was created by + overwriting a REG rtx which is always shared. */ + sub = copy_rtx (XEXP (XEXP (x, 0), 0)); + if (validate_change (insn, loc, sub, 0) + || validate_replace_rtx (x, sub, insn)) + return true; - /* Rewrite the PARM_DECL's type with its component. */ - TREE_TYPE (p) = subtype; - DECL_ARG_TYPE (p) = TREE_TYPE (DECL_ARG_TYPE (p)); - DECL_MODE (p) = VOIDmode; - DECL_SIZE (p) = NULL; - DECL_SIZE_UNIT (p) = NULL; - /* If this arg must go in memory, put it in a pseudo here. - We can't allow it to go in memory as per normal parms, - because the usual place might not have the imag part - adjacent to the real part. */ - DECL_ARTIFICIAL (p) = addressable; - DECL_IGNORED_P (p) = addressable; - TREE_ADDRESSABLE (p) = 0; - layout_decl (p, 0); + start_sequence (); - /* Build a second synthetic decl. */ - decl = build_decl (PARM_DECL, NULL_TREE, subtype); - DECL_ARG_TYPE (decl) = DECL_ARG_TYPE (p); - DECL_ARTIFICIAL (decl) = addressable; - DECL_IGNORED_P (decl) = addressable; - layout_decl (decl, 0); + /* If SUB is a hard or virtual register, try it as a pseudo-register. + Otherwise, perhaps SUB is an expression, so generate code to compute + it. */ + if (GET_CODE (sub) == REG && REGNO (sub) <= LAST_VIRTUAL_REGISTER) + sub = copy_to_reg (sub); + else + sub = force_operand (sub, NULL_RTX); - /* Splice it in; skip the new decl. */ - TREE_CHAIN (decl) = TREE_CHAIN (p); - TREE_CHAIN (p) = decl; - p = decl; - } + if (! validate_change (insn, loc, sub, 0) + && ! validate_replace_rtx (x, sub, insn)) + abort (); + + insns = get_insns (); + end_sequence (); + emit_insn_before (insns, insn); + return true; } - return args; -} + else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force) + { + rtx sub = XEXP (XEXP (x, 0), 0); -/* A subroutine of assign_parms. Adjust the parameter list to incorporate - the hidden struct return argument, and (abi willing) complex args. - Return the new parameter list. */ + if (GET_CODE (sub) == MEM) + sub = adjust_address_nv (sub, GET_MODE (x), 0); + else if (GET_CODE (sub) == REG + && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode)) + ; + else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub)) + { + int size_x, size_sub; -static tree -assign_parms_augmented_arg_list (struct assign_parm_data_all *all) -{ - tree fndecl = current_function_decl; - tree fntype = TREE_TYPE (fndecl); - tree fnargs = DECL_ARGUMENTS (fndecl); + if (may_postpone) + { + /* Postpone for now, so that we do not emit bitfield arithmetics + unless there is some benefit from it. */ + if (!postponed_insns || XEXP (postponed_insns, 0) != insn) + postponed_insns = alloc_INSN_LIST (insn, postponed_insns); + return true; + } - /* If struct value address is treated as the first argument, make it so. */ - if (aggregate_value_p (DECL_RESULT (fndecl), fndecl) - && ! current_function_returns_pcc_struct - && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0) - { - tree type = build_pointer_type (TREE_TYPE (fntype)); - tree decl; + if (!insn) + { + /* When processing REG_NOTES look at the list of + replacements done on the insn to find the register that X + was replaced by. */ + rtx tem; + + for (tem = purge_bitfield_addressof_replacements; + tem != NULL_RTX; + tem = XEXP (XEXP (tem, 1), 1)) + if (rtx_equal_p (x, XEXP (tem, 0))) + { + *loc = XEXP (XEXP (tem, 1), 0); + return true; + } + + /* See comment for purge_addressof_replacements. */ + for (tem = purge_addressof_replacements; + tem != NULL_RTX; + tem = XEXP (XEXP (tem, 1), 1)) + if (rtx_equal_p (XEXP (x, 0), XEXP (tem, 0))) + { + rtx z = XEXP (XEXP (tem, 1), 0); + + if (GET_MODE (x) == GET_MODE (z) + || (GET_CODE (XEXP (XEXP (tem, 1), 0)) != REG + && GET_CODE (XEXP (XEXP (tem, 1), 0)) != SUBREG)) + abort (); + + /* It can happen that the note may speak of things + in a wider (or just different) mode than the + code did. This is especially true of + REG_RETVAL. */ + + if (GET_CODE (z) == SUBREG && SUBREG_BYTE (z) == 0) + z = SUBREG_REG (z); + + if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD + && (GET_MODE_SIZE (GET_MODE (x)) + > GET_MODE_SIZE (GET_MODE (z)))) + { + /* This can occur as a result in invalid + pointer casts, e.g. float f; ... + *(long long int *)&f. + ??? We could emit a warning here, but + without a line number that wouldn't be + very helpful. */ + z = gen_rtx_SUBREG (GET_MODE (x), z, 0); + } + else + z = gen_lowpart (GET_MODE (x), z); + + *loc = z; + return true; + } + + /* When we are processing the REG_NOTES of the last instruction + of a libcall, there will be typically no replacements + for that insn; the replacements happened before, piecemeal + fashion. OTOH we are not interested in the details of + this for the REG_EQUAL note, we want to know the big picture, + which can be succinctly described with a simple SUBREG. + Note that removing the REG_EQUAL note is not an option + on the last insn of a libcall, so we must do a replacement. */ + + /* In compile/990107-1.c:7 compiled at -O1 -m1 for sh-elf, + we got + (mem:DI (addressof:SI (reg/v:DF 160) 159 0x401c8510) + [0 S8 A32]), which can be expressed with a simple + same-size subreg */ + if ((GET_MODE_SIZE (GET_MODE (x)) + <= GET_MODE_SIZE (GET_MODE (sub))) + /* Again, invalid pointer casts (as in + compile/990203-1.c) can require paradoxical + subregs. */ + || (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD + && (GET_MODE_SIZE (GET_MODE (x)) + > GET_MODE_SIZE (GET_MODE (sub))) + && libcall)) + { + *loc = gen_rtx_SUBREG (GET_MODE (x), sub, 0); + return true; + } + /* ??? Are there other cases we should handle? */ + + /* Sometimes we may not be able to find the replacement. For + example when the original insn was a MEM in a wider mode, + and the note is part of a sign extension of a narrowed + version of that MEM. Gcc testcase compile/990829-1.c can + generate an example of this situation. Rather than complain + we return false, which will prompt our caller to remove the + offending note. */ + return false; + } - decl = build_decl (PARM_DECL, NULL_TREE, type); - DECL_ARG_TYPE (decl) = type; - DECL_ARTIFICIAL (decl) = 1; - DECL_IGNORED_P (decl) = 1; + size_x = GET_MODE_BITSIZE (GET_MODE (x)); + size_sub = GET_MODE_BITSIZE (GET_MODE (sub)); - TREE_CHAIN (decl) = fnargs; - fnargs = decl; - all->function_result_decl = decl; - } + /* Do not frob unchanging MEMs. If a later reference forces the + pseudo to the stack, we can wind up with multiple writes to + an unchanging memory, which is invalid. */ + if (RTX_UNCHANGING_P (x) && size_x != size_sub) + ; - all->orig_fnargs = fnargs; + /* Don't even consider working with paradoxical subregs, + or the moral equivalent seen here. */ + else if (size_x <= size_sub + && int_mode_for_mode (GET_MODE (sub)) != BLKmode) + { + /* Do a bitfield insertion to mirror what would happen + in memory. */ - /* If the target wants to split complex arguments into scalars, do so. */ - if (targetm.calls.split_complex_arg) - fnargs = split_complex_args (fnargs); + rtx val, seq; - return fnargs; -} + if (store) + { + rtx p = PREV_INSN (insn); -/* A subroutine of assign_parms. Examine PARM and pull out type and mode - data for the parameter. Incorporate ABI specifics such as pass-by- - reference and type promotion. */ + start_sequence (); + val = gen_reg_rtx (GET_MODE (x)); + if (! validate_change (insn, loc, val, 0)) + { + /* Discard the current sequence and put the + ADDRESSOF on stack. */ + end_sequence (); + goto give_up; + } + seq = get_insns (); + end_sequence (); + emit_insn_before (seq, insn); + compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (), + insn, ht); + + start_sequence (); + store_bit_field (sub, size_x, 0, GET_MODE (x), + val, GET_MODE_SIZE (GET_MODE (sub))); + + /* Make sure to unshare any shared rtl that store_bit_field + might have created. */ + unshare_all_rtl_again (get_insns ()); + + seq = get_insns (); + end_sequence (); + p = emit_insn_after (seq, insn); + if (NEXT_INSN (insn)) + compute_insns_for_mem (NEXT_INSN (insn), + p ? NEXT_INSN (p) : NULL_RTX, + ht); + } + else + { + rtx p = PREV_INSN (insn); -static void -assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm, - struct assign_parm_data_one *data) -{ - tree nominal_type, passed_type; - enum machine_mode nominal_mode, passed_mode, promoted_mode; - - memset (data, 0, sizeof (*data)); - - /* NAMED_ARG is a mis-nomer. We really mean 'non-varadic'. */ - if (!current_function_stdarg) - data->named_arg = 1; /* No varadic parms. */ - else if (TREE_CHAIN (parm)) - data->named_arg = 1; /* Not the last non-varadic parm. */ - else if (targetm.calls.strict_argument_naming (&all->args_so_far)) - data->named_arg = 1; /* Only varadic ones are unnamed. */ - else - data->named_arg = 0; /* Treat as varadic. */ - - nominal_type = TREE_TYPE (parm); - passed_type = DECL_ARG_TYPE (parm); - - /* Look out for errors propagating this far. Also, if the parameter's - type is void then its value doesn't matter. */ - if (TREE_TYPE (parm) == error_mark_node - /* This can happen after weird syntax errors - or if an enum type is defined among the parms. */ - || TREE_CODE (parm) != PARM_DECL - || passed_type == NULL - || VOID_TYPE_P (nominal_type)) - { - nominal_type = passed_type = void_type_node; - nominal_mode = passed_mode = promoted_mode = VOIDmode; - goto egress; - } + start_sequence (); + val = extract_bit_field (sub, size_x, 0, 1, NULL_RTX, + GET_MODE (x), GET_MODE (x), + GET_MODE_SIZE (GET_MODE (sub))); - /* Find mode of arg as it is passed, and mode of arg as it should be - during execution of this function. */ - passed_mode = TYPE_MODE (passed_type); - nominal_mode = TYPE_MODE (nominal_type); - - /* If the parm is to be passed as a transparent union, use the type of - the first field for the tests below. We have already verified that - the modes are the same. */ - if (TREE_CODE (passed_type) == UNION_TYPE - && TYPE_TRANSPARENT_UNION (passed_type)) - passed_type = TREE_TYPE (TYPE_FIELDS (passed_type)); - - /* See if this arg was passed by invisible reference. */ - if (pass_by_reference (&all->args_so_far, passed_mode, - passed_type, data->named_arg)) - { - passed_type = nominal_type = build_pointer_type (passed_type); - data->passed_pointer = true; - passed_mode = nominal_mode = Pmode; + if (! validate_change (insn, loc, val, 0)) + { + /* Discard the current sequence and put the + ADDRESSOF on stack. */ + end_sequence (); + goto give_up; + } + + seq = get_insns (); + end_sequence (); + emit_insn_before (seq, insn); + compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (), + insn, ht); + } + + /* Remember the replacement so that the same one can be done + on the REG_NOTES. */ + purge_bitfield_addressof_replacements + = gen_rtx_EXPR_LIST (VOIDmode, x, + gen_rtx_EXPR_LIST + (VOIDmode, val, + purge_bitfield_addressof_replacements)); + + /* We replaced with a reg -- all done. */ + return true; + } + } + + else if (validate_change (insn, loc, sub, 0)) + { + /* Remember the replacement so that the same one can be done + on the REG_NOTES. */ + if (GET_CODE (sub) == REG || GET_CODE (sub) == SUBREG) + { + rtx tem; + + for (tem = purge_addressof_replacements; + tem != NULL_RTX; + tem = XEXP (XEXP (tem, 1), 1)) + if (rtx_equal_p (XEXP (x, 0), XEXP (tem, 0))) + { + XEXP (XEXP (tem, 1), 0) = sub; + return true; + } + purge_addressof_replacements + = gen_rtx (EXPR_LIST, VOIDmode, XEXP (x, 0), + gen_rtx_EXPR_LIST (VOIDmode, sub, + purge_addressof_replacements)); + return true; + } + goto restart; + } } - /* Find mode as it is passed by the ABI. */ - promoted_mode = passed_mode; - if (targetm.calls.promote_function_args (TREE_TYPE (current_function_decl))) + give_up: + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) { - int unsignedp = TYPE_UNSIGNED (passed_type); - promoted_mode = promote_mode (passed_type, promoted_mode, - &unsignedp, 1); + if (*fmt == 'e') + result &= purge_addressof_1 (&XEXP (x, i), insn, force, 0, + may_postpone, ht); + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + result &= purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0, + may_postpone, ht); } - egress: - data->nominal_type = nominal_type; - data->passed_type = passed_type; - data->nominal_mode = nominal_mode; - data->passed_mode = passed_mode; - data->promoted_mode = promoted_mode; + return result; } -/* A subroutine of assign_parms. Invoke setup_incoming_varargs. */ +/* Return a hash value for K, a REG. */ -static void -assign_parms_setup_varargs (struct assign_parm_data_all *all, - struct assign_parm_data_one *data, bool no_rtl) +static hashval_t +insns_for_mem_hash (const void *k) { - int varargs_pretend_bytes = 0; - - targetm.calls.setup_incoming_varargs (&all->args_so_far, - data->promoted_mode, - data->passed_type, - &varargs_pretend_bytes, no_rtl); - - /* If the back-end has requested extra stack space, record how much is - needed. Do not change pretend_args_size otherwise since it may be - nonzero from an earlier partial argument. */ - if (varargs_pretend_bytes > 0) - all->pretend_args_size = varargs_pretend_bytes; + /* Use the address of the key for the hash value. */ + struct insns_for_mem_entry *m = (struct insns_for_mem_entry *) k; + return htab_hash_pointer (m->key); } -/* A subroutine of assign_parms. Set DATA->ENTRY_PARM corresponding to - the incoming location of the current parameter. */ +/* Return nonzero if K1 and K2 (two REGs) are the same. */ -static void -assign_parm_find_entry_rtl (struct assign_parm_data_all *all, - struct assign_parm_data_one *data) +static int +insns_for_mem_comp (const void *k1, const void *k2) { - HOST_WIDE_INT pretend_bytes = 0; - rtx entry_parm; - bool in_regs; + struct insns_for_mem_entry *m1 = (struct insns_for_mem_entry *) k1; + struct insns_for_mem_entry *m2 = (struct insns_for_mem_entry *) k2; + return m1->key == m2->key; +} - if (data->promoted_mode == VOIDmode) - { - data->entry_parm = data->stack_parm = const0_rtx; - return; - } +struct insns_for_mem_walk_info +{ + /* The hash table that we are using to record which INSNs use which + MEMs. */ + htab_t ht; -#ifdef FUNCTION_INCOMING_ARG - entry_parm = FUNCTION_INCOMING_ARG (all->args_so_far, data->promoted_mode, - data->passed_type, data->named_arg); -#else - entry_parm = FUNCTION_ARG (all->args_so_far, data->promoted_mode, - data->passed_type, data->named_arg); -#endif + /* The INSN we are currently processing. */ + rtx insn; - if (entry_parm == 0) - data->promoted_mode = data->passed_mode; + /* Zero if we are walking to find ADDRESSOFs, one if we are walking + to find the insns that use the REGs in the ADDRESSOFs. */ + int pass; +}; - /* Determine parm's home in the stack, in case it arrives in the stack - or we should pretend it did. Compute the stack position and rtx where - the argument arrives and its size. +/* Called from compute_insns_for_mem via for_each_rtx. If R is a REG + that might be used in an ADDRESSOF expression, record this INSN in + the hash table given by DATA (which is really a pointer to an + insns_for_mem_walk_info structure). */ - There is one complexity here: If this was a parameter that would - have been passed in registers, but wasn't only because it is - __builtin_va_alist, we want locate_and_pad_parm to treat it as if - it came in a register so that REG_PARM_STACK_SPACE isn't skipped. - In this case, we call FUNCTION_ARG with NAMED set to 1 instead of 0 - as it was the previous time. */ - in_regs = entry_parm != 0; -#ifdef STACK_PARMS_IN_REG_PARM_AREA - in_regs = true; -#endif - if (!in_regs && !data->named_arg) +static int +insns_for_mem_walk (rtx *r, void *data) +{ + struct insns_for_mem_walk_info *ifmwi + = (struct insns_for_mem_walk_info *) data; + struct insns_for_mem_entry tmp; + tmp.insns = NULL_RTX; + + if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF + && GET_CODE (XEXP (*r, 0)) == REG) { - if (targetm.calls.pretend_outgoing_varargs_named (&all->args_so_far)) + void **e; + tmp.key = XEXP (*r, 0); + e = htab_find_slot (ifmwi->ht, &tmp, INSERT); + if (*e == NULL) { - rtx tem; -#ifdef FUNCTION_INCOMING_ARG - tem = FUNCTION_INCOMING_ARG (all->args_so_far, data->promoted_mode, - data->passed_type, true); -#else - tem = FUNCTION_ARG (all->args_so_far, data->promoted_mode, - data->passed_type, true); -#endif - in_regs = tem != NULL; + *e = ggc_alloc (sizeof (tmp)); + memcpy (*e, &tmp, sizeof (tmp)); } } + else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG) + { + struct insns_for_mem_entry *ifme; + tmp.key = *r; + ifme = htab_find (ifmwi->ht, &tmp); + + /* If we have not already recorded this INSN, do so now. Since + we process the INSNs in order, we know that if we have + recorded it it must be at the front of the list. */ + if (ifme && (!ifme->insns || XEXP (ifme->insns, 0) != ifmwi->insn)) + ifme->insns = gen_rtx_EXPR_LIST (VOIDmode, ifmwi->insn, + ifme->insns); + } - /* If this parameter was passed both in registers and in the stack, use - the copy on the stack. */ - if (targetm.calls.must_pass_in_stack (data->promoted_mode, - data->passed_type)) - entry_parm = 0; + return 0; +} - if (entry_parm) - { - int partial; +/* Walk the INSNS, until we reach LAST_INSN, recording which INSNs use + which REGs in HT. */ - partial = targetm.calls.arg_partial_bytes (&all->args_so_far, - data->promoted_mode, - data->passed_type, - data->named_arg); - data->partial = partial; +static void +compute_insns_for_mem (rtx insns, rtx last_insn, htab_t ht) +{ + rtx insn; + struct insns_for_mem_walk_info ifmwi; + ifmwi.ht = ht; - /* The caller might already have allocated stack space for the - register parameters. */ - if (partial != 0 && all->reg_parm_stack_space == 0) + for (ifmwi.pass = 0; ifmwi.pass < 2; ++ifmwi.pass) + for (insn = insns; insn != last_insn; insn = NEXT_INSN (insn)) + if (INSN_P (insn)) { - /* Part of this argument is passed in registers and part - is passed on the stack. Ask the prologue code to extend - the stack part so that we can recreate the full value. - - PRETEND_BYTES is the size of the registers we need to store. - CURRENT_FUNCTION_PRETEND_ARGS_SIZE is the amount of extra - stack space that the prologue should allocate. - - Internally, gcc assumes that the argument pointer is aligned - to STACK_BOUNDARY bits. This is used both for alignment - optimizations (see init_emit) and to locate arguments that are - aligned to more than PARM_BOUNDARY bits. We must preserve this - invariant by rounding CURRENT_FUNCTION_PRETEND_ARGS_SIZE up to - a stack boundary. */ - - /* We assume at most one partial arg, and it must be the first - argument on the stack. */ - gcc_assert (!all->extra_pretend_bytes && !all->pretend_args_size); - - pretend_bytes = partial; - all->pretend_args_size = CEIL_ROUND (pretend_bytes, STACK_BYTES); - - /* We want to align relative to the actual stack pointer, so - don't include this in the stack size until later. */ - all->extra_pretend_bytes = all->pretend_args_size; + ifmwi.insn = insn; + for_each_rtx (&insn, insns_for_mem_walk, &ifmwi); } - } - - locate_and_pad_parm (data->promoted_mode, data->passed_type, in_regs, - entry_parm ? data->partial : 0, current_function_decl, - &all->stack_args_size, &data->locate); +} - /* Adjust offsets to include the pretend args. */ - pretend_bytes = all->extra_pretend_bytes - pretend_bytes; - data->locate.slot_offset.constant += pretend_bytes; - data->locate.offset.constant += pretend_bytes; +/* Helper function for purge_addressof called through for_each_rtx. + Returns true iff the rtl is an ADDRESSOF. */ - data->entry_parm = entry_parm; +static int +is_addressof (rtx *rtl, void *data ATTRIBUTE_UNUSED) +{ + return GET_CODE (*rtl) == ADDRESSOF; } -/* A subroutine of assign_parms. If there is actually space on the stack - for this parm, count it in stack_args_size and return true. */ +/* Eliminate all occurrences of ADDRESSOF from INSNS. Elide any remaining + (MEM (ADDRESSOF)) patterns, and force any needed registers into the + stack. */ -static bool -assign_parm_is_stack_parm (struct assign_parm_data_all *all, - struct assign_parm_data_one *data) +void +purge_addressof (rtx insns) { - /* Trivially true if we've no incoming register. */ - if (data->entry_parm == NULL) - ; - /* Also true if we're partially in registers and partially not, - since we've arranged to drop the entire argument on the stack. */ - else if (data->partial != 0) - ; - /* Also true if the target says that it's passed in both registers - and on the stack. */ - else if (GET_CODE (data->entry_parm) == PARALLEL - && XEXP (XVECEXP (data->entry_parm, 0, 0), 0) == NULL_RTX) - ; - /* Also true if the target says that there's stack allocated for - all register parameters. */ - else if (all->reg_parm_stack_space > 0) - ; - /* Otherwise, no, this parameter has no ABI defined stack slot. */ - else - return false; + rtx insn, tmp; + htab_t ht; - all->stack_args_size.constant += data->locate.size.constant; - if (data->locate.size.var) - ADD_PARM_SIZE (all->stack_args_size, data->locate.size.var); + /* When we actually purge ADDRESSOFs, we turn REGs into MEMs. That + requires a fixup pass over the instruction stream to correct + INSNs that depended on the REG being a REG, and not a MEM. But, + these fixup passes are slow. Furthermore, most MEMs are not + mentioned in very many instructions. So, we speed up the process + by pre-calculating which REGs occur in which INSNs; that allows + us to perform the fixup passes much more quickly. */ + ht = htab_create_ggc (1000, insns_for_mem_hash, insns_for_mem_comp, NULL); + compute_insns_for_mem (insns, NULL_RTX, ht); - return true; -} + postponed_insns = NULL; -/* A subroutine of assign_parms. Given that this parameter is allocated - stack space by the ABI, find it. */ + for (insn = insns; insn; insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + { + if (! purge_addressof_1 (&PATTERN (insn), insn, + asm_noperands (PATTERN (insn)) > 0, 0, 1, ht)) + /* If we could not replace the ADDRESSOFs in the insn, + something is wrong. */ + abort (); -static void -assign_parm_find_stack_rtl (tree parm, struct assign_parm_data_one *data) -{ - rtx offset_rtx, stack_parm; - unsigned int align, boundary; + if (! purge_addressof_1 (®_NOTES (insn), NULL_RTX, 0, 0, 0, ht)) + { + /* If we could not replace the ADDRESSOFs in the insn's notes, + we can just remove the offending notes instead. */ + rtx note; - /* If we're passing this arg using a reg, make its stack home the - aligned stack slot. */ - if (data->entry_parm) - offset_rtx = ARGS_SIZE_RTX (data->locate.slot_offset); - else - offset_rtx = ARGS_SIZE_RTX (data->locate.offset); + for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) + { + /* If we find a REG_RETVAL note then the insn is a libcall. + Such insns must have REG_EQUAL notes as well, in order + for later passes of the compiler to work. So it is not + safe to delete the notes here, and instead we abort. */ + if (REG_NOTE_KIND (note) == REG_RETVAL) + abort (); + if (for_each_rtx (¬e, is_addressof, NULL)) + remove_note (insn, note); + } + } + } - stack_parm = current_function_internal_arg_pointer; - if (offset_rtx != const0_rtx) - stack_parm = gen_rtx_PLUS (Pmode, stack_parm, offset_rtx); - stack_parm = gen_rtx_MEM (data->promoted_mode, stack_parm); + /* Process the postponed insns. */ + while (postponed_insns) + { + insn = XEXP (postponed_insns, 0); + tmp = postponed_insns; + postponed_insns = XEXP (postponed_insns, 1); + free_INSN_LIST_node (tmp); + + if (! purge_addressof_1 (&PATTERN (insn), insn, + asm_noperands (PATTERN (insn)) > 0, 0, 0, ht)) + abort (); + } + + /* Clean up. */ + purge_bitfield_addressof_replacements = 0; + purge_addressof_replacements = 0; + + /* REGs are shared. purge_addressof will destructively replace a REG + with a MEM, which creates shared MEMs. - set_mem_attributes (stack_parm, parm, 1); + Unfortunately, the children of put_reg_into_stack assume that MEMs + referring to the same stack slot are shared (fixup_var_refs and + the associated hash table code). + + So, we have to do another unsharing pass after we have flushed any + REGs that had their address taken into the stack. + + It may be worth tracking whether or not we converted any REGs into + MEMs to avoid this overhead when it is not needed. */ + unshare_all_rtl_again (get_insns ()); +} + +/* Convert a SET of a hard subreg to a set of the appropriate hard + register. A subroutine of purge_hard_subreg_sets. */ - boundary = data->locate.boundary; - align = BITS_PER_UNIT; +static void +purge_single_hard_subreg_set (rtx pattern) +{ + rtx reg = SET_DEST (pattern); + enum machine_mode mode = GET_MODE (SET_DEST (pattern)); + int offset = 0; - /* If we're padding upward, we know that the alignment of the slot - is FUNCTION_ARG_BOUNDARY. If we're using slot_offset, we're - intentionally forcing upward padding. Otherwise we have to come - up with a guess at the alignment based on OFFSET_RTX. */ - if (data->locate.where_pad != downward || data->entry_parm) - align = boundary; - else if (GET_CODE (offset_rtx) == CONST_INT) + if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG + && REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER) { - align = INTVAL (offset_rtx) * BITS_PER_UNIT | boundary; - align = align & -align; + offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)), + GET_MODE (SUBREG_REG (reg)), + SUBREG_BYTE (reg), + GET_MODE (reg)); + reg = SUBREG_REG (reg); } - set_mem_align (stack_parm, align); - if (data->entry_parm) - set_reg_attrs_for_parm (data->entry_parm, stack_parm); - data->stack_parm = stack_parm; + if (GET_CODE (reg) == REG && REGNO (reg) < FIRST_PSEUDO_REGISTER) + { + reg = gen_rtx_REG (mode, REGNO (reg) + offset); + SET_DEST (pattern) = reg; + } } -/* A subroutine of assign_parms. Adjust DATA->ENTRY_RTL such that it's - always valid and contiguous. */ +/* Eliminate all occurrences of SETs of hard subregs from INSNS. The + only such SETs that we expect to see are those left in because + integrate can't handle sets of parts of a return value register. -static void -assign_parm_adjust_entry_rtl (struct assign_parm_data_one *data) + We don't use alter_subreg because we only want to eliminate subregs + of hard registers. */ + +void +purge_hard_subreg_sets (rtx insn) { - rtx entry_parm = data->entry_parm; - rtx stack_parm = data->stack_parm; - - /* If this parm was passed part in regs and part in memory, pretend it - arrived entirely in memory by pushing the register-part onto the stack. - In the special case of a DImode or DFmode that is split, we could put - it together in a pseudoreg directly, but for now that's not worth - bothering with. */ - if (data->partial != 0) + for (; insn; insn = NEXT_INSN (insn)) { - /* Handle calls that pass values in multiple non-contiguous - locations. The Irix 6 ABI has examples of this. */ - if (GET_CODE (entry_parm) == PARALLEL) - emit_group_store (validize_mem (stack_parm), entry_parm, - data->passed_type, - int_size_in_bytes (data->passed_type)); - else + if (INSN_P (insn)) { - gcc_assert (data->partial % UNITS_PER_WORD == 0); - move_block_from_reg (REGNO (entry_parm), validize_mem (stack_parm), - data->partial / UNITS_PER_WORD); + rtx pattern = PATTERN (insn); + switch (GET_CODE (pattern)) + { + case SET: + if (GET_CODE (SET_DEST (pattern)) == SUBREG) + purge_single_hard_subreg_set (pattern); + break; + case PARALLEL: + { + int j; + for (j = XVECLEN (pattern, 0) - 1; j >= 0; j--) + { + rtx inner_pattern = XVECEXP (pattern, 0, j); + if (GET_CODE (inner_pattern) == SET + && GET_CODE (SET_DEST (inner_pattern)) == SUBREG) + purge_single_hard_subreg_set (inner_pattern); + } + } + break; + default: + break; + } } - - entry_parm = stack_parm; } +} + +/* Pass through the INSNS of function FNDECL and convert virtual register + references to hard register references. */ - /* If we didn't decide this parm came in a register, by default it came - on the stack. */ - else if (entry_parm == NULL) - entry_parm = stack_parm; - - /* When an argument is passed in multiple locations, we can't make use - of this information, but we can save some copying if the whole argument - is passed in a single register. */ - else if (GET_CODE (entry_parm) == PARALLEL - && data->nominal_mode != BLKmode - && data->passed_mode != BLKmode) - { - size_t i, len = XVECLEN (entry_parm, 0); - - for (i = 0; i < len; i++) - if (XEXP (XVECEXP (entry_parm, 0, i), 0) != NULL_RTX - && REG_P (XEXP (XVECEXP (entry_parm, 0, i), 0)) - && (GET_MODE (XEXP (XVECEXP (entry_parm, 0, i), 0)) - == data->passed_mode) - && INTVAL (XEXP (XVECEXP (entry_parm, 0, i), 1)) == 0) - { - entry_parm = XEXP (XVECEXP (entry_parm, 0, i), 0); - break; - } - } +void +instantiate_virtual_regs (tree fndecl, rtx insns) +{ + rtx insn; + unsigned int i; + + /* Compute the offsets to use for this function. */ + in_arg_offset = FIRST_PARM_OFFSET (fndecl); + var_offset = STARTING_FRAME_OFFSET; + dynamic_offset = STACK_DYNAMIC_OFFSET (fndecl); + out_arg_offset = STACK_POINTER_OFFSET; + cfa_offset = ARG_POINTER_CFA_OFFSET (fndecl); + + /* Scan all variables and parameters of this function. For each that is + in memory, instantiate all virtual registers if the result is a valid + address. If not, we do it later. That will handle most uses of virtual + regs on many machines. */ + instantiate_decls (fndecl, 1); + + /* Initialize recognition, indicating that volatile is OK. */ + init_recog (); - data->entry_parm = entry_parm; + /* Scan through all the insns, instantiating every virtual register still + present. */ + for (insn = insns; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + instantiate_virtual_regs_1 (&PATTERN (insn), insn, 1); + if (INSN_DELETED_P (insn)) + continue; + instantiate_virtual_regs_1 (®_NOTES (insn), NULL_RTX, 0); + /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE. */ + if (GET_CODE (insn) == CALL_INSN) + instantiate_virtual_regs_1 (&CALL_INSN_FUNCTION_USAGE (insn), + NULL_RTX, 0); + + /* Past this point all ASM statements should match. Verify that + to avoid failures later in the compilation process. */ + if (asm_noperands (PATTERN (insn)) >= 0 + && ! check_asm_operands (PATTERN (insn))) + instantiate_virtual_regs_lossage (insn); + } + + /* Instantiate the stack slots for the parm registers, for later use in + addressof elimination. */ + for (i = 0; i < max_parm_reg; ++i) + if (parm_reg_stack_loc[i]) + instantiate_virtual_regs_1 (&parm_reg_stack_loc[i], NULL_RTX, 0); + + /* Now instantiate the remaining register equivalences for debugging info. + These will not be valid addresses. */ + instantiate_decls (fndecl, 0); + + /* Indicate that, from now on, assign_stack_local should use + frame_pointer_rtx. */ + virtuals_instantiated = 1; } -/* A subroutine of assign_parms. Adjust DATA->STACK_RTL such that it's - always valid and properly aligned. */ +/* Scan all decls in FNDECL (both variables and parameters) and instantiate + all virtual registers in their DECL_RTL's. + + If VALID_ONLY, do this only if the resulting address is still valid. + Otherwise, always do it. */ static void -assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data) +instantiate_decls (tree fndecl, int valid_only) { - rtx stack_parm = data->stack_parm; - - /* If we can't trust the parm stack slot to be aligned enough for its - ultimate type, don't use that slot after entry. We'll make another - stack slot, if we need one. */ - if (stack_parm - && ((STRICT_ALIGNMENT - && GET_MODE_ALIGNMENT (data->nominal_mode) > MEM_ALIGN (stack_parm)) - || (data->nominal_type - && TYPE_ALIGN (data->nominal_type) > MEM_ALIGN (stack_parm) - && MEM_ALIGN (stack_parm) < PREFERRED_STACK_BOUNDARY))) - stack_parm = NULL; - - /* If parm was passed in memory, and we need to convert it on entry, - don't store it back in that same slot. */ - else if (data->entry_parm == stack_parm - && data->nominal_mode != BLKmode - && data->nominal_mode != data->passed_mode) - stack_parm = NULL; - - /* If stack protection is in effect for this function, don't leave any - pointers in their passed stack slots. */ - else if (cfun->stack_protect_guard - && (flag_stack_protect == 2 - || data->passed_pointer - || POINTER_TYPE_P (data->nominal_type))) - stack_parm = NULL; - - data->stack_parm = stack_parm; + tree decl; + + /* Process all parameters of the function. */ + for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl)) + { + HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl)); + HOST_WIDE_INT size_rtl; + + instantiate_decl (DECL_RTL (decl), size, valid_only); + + /* If the parameter was promoted, then the incoming RTL mode may be + larger than the declared type size. We must use the larger of + the two sizes. */ + size_rtl = GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl))); + size = MAX (size_rtl, size); + instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only); + } + + /* Now process all variables defined in the function or its subblocks. */ + instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only); } -/* A subroutine of assign_parms. Return true if the current parameter - should be stored as a BLKmode in the current frame. */ +/* Subroutine of instantiate_decls: Process all decls in the given + BLOCK node and all its subblocks. */ -static bool -assign_parm_setup_block_p (struct assign_parm_data_one *data) +static void +instantiate_decls_1 (tree let, int valid_only) { - if (data->nominal_mode == BLKmode) - return true; - if (GET_CODE (data->entry_parm) == PARALLEL) - return true; + tree t; -#ifdef BLOCK_REG_PADDING - /* Only assign_parm_setup_block knows how to deal with register arguments - that are padded at the least significant end. */ - if (REG_P (data->entry_parm) - && GET_MODE_SIZE (data->promoted_mode) < UNITS_PER_WORD - && (BLOCK_REG_PADDING (data->passed_mode, data->passed_type, 1) - == (BYTES_BIG_ENDIAN ? upward : downward))) - return true; -#endif + for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) + if (DECL_RTL_SET_P (t)) + instantiate_decl (DECL_RTL (t), + int_size_in_bytes (TREE_TYPE (t)), + valid_only); - return false; + /* Process all subblocks. */ + for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t)) + instantiate_decls_1 (t, valid_only); } -/* A subroutine of assign_parms. Arrange for the parameter to be - present and valid in DATA->STACK_RTL. */ +/* Subroutine of the preceding procedures: Given RTL representing a + decl and the size of the object, do any instantiation required. + + If VALID_ONLY is nonzero, it means that the RTL should only be + changed if the new address is valid. */ static void -assign_parm_setup_block (struct assign_parm_data_all *all, - tree parm, struct assign_parm_data_one *data) +instantiate_decl (rtx x, HOST_WIDE_INT size, int valid_only) { - rtx entry_parm = data->entry_parm; - rtx stack_parm = data->stack_parm; - HOST_WIDE_INT size; - HOST_WIDE_INT size_stored; - rtx orig_entry_parm = entry_parm; + enum machine_mode mode; + rtx addr; - if (GET_CODE (entry_parm) == PARALLEL) - entry_parm = emit_group_move_into_temps (entry_parm); + if (x == 0) + return; - /* If we've a non-block object that's nevertheless passed in parts, - reconstitute it in register operations rather than on the stack. */ - if (GET_CODE (entry_parm) == PARALLEL - && data->nominal_mode != BLKmode) + /* If this is a CONCAT, recurse for the pieces. */ + if (GET_CODE (x) == CONCAT) { - rtx elt0 = XEXP (XVECEXP (orig_entry_parm, 0, 0), 0); + instantiate_decl (XEXP (x, 0), size / 2, valid_only); + instantiate_decl (XEXP (x, 1), size / 2, valid_only); + return; + } - if ((XVECLEN (entry_parm, 0) > 1 - || hard_regno_nregs[REGNO (elt0)][GET_MODE (elt0)] > 1) - && use_register_for_decl (parm)) - { - rtx parmreg = gen_reg_rtx (data->nominal_mode); + /* If this is not a MEM, no need to do anything. Similarly if the + address is a constant or a register that is not a virtual register. */ + if (GET_CODE (x) != MEM) + return; - push_to_sequence (all->conversion_insns); + addr = XEXP (x, 0); + if (CONSTANT_P (addr) + || (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == REG) + || (GET_CODE (addr) == REG + && (REGNO (addr) < FIRST_VIRTUAL_REGISTER + || REGNO (addr) > LAST_VIRTUAL_REGISTER))) + return; - /* For values returned in multiple registers, handle possible - incompatible calls to emit_group_store. + /* If we should only do this if the address is valid, copy the address. + We need to do this so we can undo any changes that might make the + address invalid. This copy is unfortunate, but probably can't be + avoided. */ - For example, the following would be invalid, and would have to - be fixed by the conditional below: + if (valid_only) + addr = copy_rtx (addr); - emit_group_store ((reg:SF), (parallel:DF)) - emit_group_store ((reg:SI), (parallel:DI)) + instantiate_virtual_regs_1 (&addr, NULL_RTX, 0); - An example of this are doubles in e500 v2: - (parallel:DF (expr_list (reg:SI) (const_int 0)) - (expr_list (reg:SI) (const_int 4))). */ - if (data->nominal_mode != data->passed_mode) - { - rtx t = gen_reg_rtx (GET_MODE (entry_parm)); - emit_group_store (t, entry_parm, NULL_TREE, - GET_MODE_SIZE (GET_MODE (entry_parm))); - convert_move (parmreg, t, 0); - } - else - emit_group_store (parmreg, entry_parm, data->nominal_type, - int_size_in_bytes (data->nominal_type)); + if (valid_only && size >= 0) + { + unsigned HOST_WIDE_INT decl_size = size; - all->conversion_insns = get_insns (); - end_sequence (); + /* Now verify that the resulting address is valid for every integer or + floating-point mode up to and including SIZE bytes long. We do this + since the object might be accessed in any mode and frame addresses + are shared. */ - SET_DECL_RTL (parm, parmreg); + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size; + mode = GET_MODE_WIDER_MODE (mode)) + if (! memory_address_p (mode, addr)) + return; + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); + mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size; + mode = GET_MODE_WIDER_MODE (mode)) + if (! memory_address_p (mode, addr)) return; - } } - size = int_size_in_bytes (data->passed_type); - size_stored = CEIL_ROUND (size, UNITS_PER_WORD); - if (stack_parm == 0) + /* Put back the address now that we have updated it and we either know + it is valid or we don't care whether it is valid. */ + + XEXP (x, 0) = addr; +} + +/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX + is a virtual register, return the equivalent hard register and set the + offset indirectly through the pointer. Otherwise, return 0. */ + +static rtx +instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset) +{ + rtx new; + HOST_WIDE_INT offset; + + if (x == virtual_incoming_args_rtx) + new = arg_pointer_rtx, offset = in_arg_offset; + else if (x == virtual_stack_vars_rtx) + new = frame_pointer_rtx, offset = var_offset; + else if (x == virtual_stack_dynamic_rtx) + new = stack_pointer_rtx, offset = dynamic_offset; + else if (x == virtual_outgoing_args_rtx) + new = stack_pointer_rtx, offset = out_arg_offset; + else if (x == virtual_cfa_rtx) + new = arg_pointer_rtx, offset = cfa_offset; + else + return 0; + + *poffset = offset; + return new; +} + + +/* Called when instantiate_virtual_regs has failed to update the instruction. + Usually this means that non-matching instruction has been emit, however for + asm statements it may be the problem in the constraints. */ +static void +instantiate_virtual_regs_lossage (rtx insn) +{ + if (asm_noperands (PATTERN (insn)) >= 0) { - DECL_ALIGN (parm) = MAX (DECL_ALIGN (parm), BITS_PER_WORD); - stack_parm = assign_stack_local (BLKmode, size_stored, - DECL_ALIGN (parm)); - if (GET_MODE_SIZE (GET_MODE (entry_parm)) == size) - PUT_MODE (stack_parm, GET_MODE (entry_parm)); - set_mem_attributes (stack_parm, parm, 1); + error_for_asm (insn, "impossible constraint in `asm'"); + delete_insn (insn); } + else + abort (); +} +/* Given a pointer to a piece of rtx and an optional pointer to the + containing object, instantiate any virtual registers present in it. - /* If a BLKmode arrives in registers, copy it to a stack slot. Handle - calls that pass values in multiple non-contiguous locations. */ - if (REG_P (entry_parm) || GET_CODE (entry_parm) == PARALLEL) - { - rtx mem; - - /* Note that we will be storing an integral number of words. - So we have to be careful to ensure that we allocate an - integral number of words. We do this above when we call - assign_stack_local if space was not allocated in the argument - list. If it was, this will not work if PARM_BOUNDARY is not - a multiple of BITS_PER_WORD. It isn't clear how to fix this - if it becomes a problem. Exception is when BLKmode arrives - with arguments not conforming to word_mode. */ - - if (data->stack_parm == 0) - ; - else if (GET_CODE (entry_parm) == PARALLEL) - ; - else - gcc_assert (!size || !(PARM_BOUNDARY % BITS_PER_WORD)); + If EXTRA_INSNS, we always do the replacement and generate + any extra insns before OBJECT. If it zero, we do nothing if replacement + is not valid. + + Return 1 if we either had nothing to do or if we were able to do the + needed replacement. Return 0 otherwise; we only return zero if + EXTRA_INSNS is zero. + + We first try some simple transformations to avoid the creation of extra + pseudos. */ + +static int +instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns) +{ + rtx x; + RTX_CODE code; + rtx new = 0; + HOST_WIDE_INT offset = 0; + rtx temp; + rtx seq; + int i, j; + const char *fmt; + + /* Re-start here to avoid recursion in common cases. */ + restart: + + x = *loc; + if (x == 0) + return 1; + + /* We may have detected and deleted invalid asm statements. */ + if (object && INSN_P (object) && INSN_DELETED_P (object)) + return 1; - mem = validize_mem (stack_parm); + code = GET_CODE (x); - /* Handle values in multiple non-contiguous locations. */ - if (GET_CODE (entry_parm) == PARALLEL) + /* Check for some special cases. */ + switch (code) + { + case CONST_INT: + case CONST_DOUBLE: + case CONST_VECTOR: + case CONST: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + case ASM_INPUT: + case ADDR_VEC: + case ADDR_DIFF_VEC: + case RETURN: + return 1; + + case SET: + /* We are allowed to set the virtual registers. This means that + the actual register should receive the source minus the + appropriate offset. This is used, for example, in the handling + of non-local gotos. */ + if ((new = instantiate_new_reg (SET_DEST (x), &offset)) != 0) { - push_to_sequence (all->conversion_insns); - emit_group_store (mem, entry_parm, data->passed_type, size); - all->conversion_insns = get_insns (); + rtx src = SET_SRC (x); + + /* We are setting the register, not using it, so the relevant + offset is the negative of the offset to use were we using + the register. */ + offset = - offset; + instantiate_virtual_regs_1 (&src, NULL_RTX, 0); + + /* The only valid sources here are PLUS or REG. Just do + the simplest possible thing to handle them. */ + if (GET_CODE (src) != REG && GET_CODE (src) != PLUS) + { + instantiate_virtual_regs_lossage (object); + return 1; + } + + start_sequence (); + if (GET_CODE (src) != REG) + temp = force_operand (src, NULL_RTX); + else + temp = src; + temp = force_operand (plus_constant (temp, offset), NULL_RTX); + seq = get_insns (); end_sequence (); + + emit_insn_before (seq, object); + SET_DEST (x) = new; + + if (! validate_change (object, &SET_SRC (x), temp, 0) + || ! extra_insns) + instantiate_virtual_regs_lossage (object); + + return 1; } - else if (size == 0) - ; + instantiate_virtual_regs_1 (&SET_DEST (x), object, extra_insns); + loc = &SET_SRC (x); + goto restart; - /* If SIZE is that of a mode no bigger than a word, just use - that mode's store operation. */ - else if (size <= UNITS_PER_WORD) + case PLUS: + /* Handle special case of virtual register plus constant. */ + if (CONSTANT_P (XEXP (x, 1))) { - enum machine_mode mode - = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0); + rtx old, new_offset; - if (mode != BLKmode -#ifdef BLOCK_REG_PADDING - && (size == UNITS_PER_WORD - || (BLOCK_REG_PADDING (mode, data->passed_type, 1) - != (BYTES_BIG_ENDIAN ? upward : downward))) + /* Check for (plus (plus VIRT foo) (const_int)) first. */ + if (GET_CODE (XEXP (x, 0)) == PLUS) + { + if ((new = instantiate_new_reg (XEXP (XEXP (x, 0), 0), &offset))) + { + instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object, + extra_insns); + new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1)); + } + else + { + loc = &XEXP (x, 0); + goto restart; + } + } + +#ifdef POINTERS_EXTEND_UNSIGNED + /* If we have (plus (subreg (virtual-reg)) (const_int)), we know + we can commute the PLUS and SUBREG because pointers into the + frame are well-behaved. */ + else if (GET_CODE (XEXP (x, 0)) == SUBREG && GET_MODE (x) == ptr_mode + && GET_CODE (XEXP (x, 1)) == CONST_INT + && 0 != (new + = instantiate_new_reg (SUBREG_REG (XEXP (x, 0)), + &offset)) + && validate_change (object, loc, + plus_constant (gen_lowpart (ptr_mode, + new), + offset + + INTVAL (XEXP (x, 1))), + 0)) + return 1; #endif - ) + else if ((new = instantiate_new_reg (XEXP (x, 0), &offset)) == 0) { - rtx reg = gen_rtx_REG (mode, REGNO (entry_parm)); - emit_move_insn (change_address (mem, mode, 0), reg); + /* We know the second operand is a constant. Unless the + first operand is a REG (which has been already checked), + it needs to be checked. */ + if (GET_CODE (XEXP (x, 0)) != REG) + { + loc = &XEXP (x, 0); + goto restart; + } + return 1; } - /* Blocks smaller than a word on a BYTES_BIG_ENDIAN - machine must be aligned to the left before storing - to memory. Note that the previous test doesn't - handle all cases (e.g. SIZE == 3). */ - else if (size != UNITS_PER_WORD -#ifdef BLOCK_REG_PADDING - && (BLOCK_REG_PADDING (mode, data->passed_type, 1) - == downward) -#else - && BYTES_BIG_ENDIAN + new_offset = plus_constant (XEXP (x, 1), offset); + + /* If the new constant is zero, try to replace the sum with just + the register. */ + if (new_offset == const0_rtx + && validate_change (object, loc, new, 0)) + return 1; + + /* Next try to replace the register and new offset. + There are two changes to validate here and we can't assume that + in the case of old offset equals new just changing the register + will yield a valid insn. In the interests of a little efficiency, + however, we only call validate change once (we don't queue up the + changes and then call apply_change_group). */ + + old = XEXP (x, 0); + if (offset == 0 + ? ! validate_change (object, &XEXP (x, 0), new, 0) + : (XEXP (x, 0) = new, + ! validate_change (object, &XEXP (x, 1), new_offset, 0))) + { + if (! extra_insns) + { + XEXP (x, 0) = old; + return 0; + } + + /* Otherwise copy the new constant into a register and replace + constant with that register. */ + temp = gen_reg_rtx (Pmode); + XEXP (x, 0) = new; + if (validate_change (object, &XEXP (x, 1), temp, 0)) + emit_insn_before (gen_move_insn (temp, new_offset), object); + else + { + /* If that didn't work, replace this expression with a + register containing the sum. */ + + XEXP (x, 0) = old; + new = gen_rtx_PLUS (Pmode, new, new_offset); + + start_sequence (); + temp = force_operand (new, NULL_RTX); + seq = get_insns (); + end_sequence (); + + emit_insn_before (seq, object); + if (! validate_change (object, loc, temp, 0) + && ! validate_replace_rtx (x, temp, object)) + { + instantiate_virtual_regs_lossage (object); + return 1; + } + } + } + + return 1; + } + + /* Fall through to generic two-operand expression case. */ + case EXPR_LIST: + case CALL: + case COMPARE: + case MINUS: + case MULT: + case DIV: case UDIV: + case MOD: case UMOD: + case AND: case IOR: case XOR: + case ROTATERT: case ROTATE: + case ASHIFTRT: case LSHIFTRT: case ASHIFT: + case NE: case EQ: + case GE: case GT: case GEU: case GTU: + case LE: case LT: case LEU: case LTU: + if (XEXP (x, 1) && ! CONSTANT_P (XEXP (x, 1))) + instantiate_virtual_regs_1 (&XEXP (x, 1), object, extra_insns); + loc = &XEXP (x, 0); + goto restart; + + case MEM: + /* Most cases of MEM that convert to valid addresses have already been + handled by our scan of decls. The only special handling we + need here is to make a copy of the rtx to ensure it isn't being + shared if we have to change it to a pseudo. + + If the rtx is a simple reference to an address via a virtual register, + it can potentially be shared. In such cases, first try to make it + a valid address, which can also be shared. Otherwise, copy it and + proceed normally. + + First check for common cases that need no processing. These are + usually due to instantiation already being done on a previous instance + of a shared rtx. */ + + temp = XEXP (x, 0); + if (CONSTANT_ADDRESS_P (temp) +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + || temp == arg_pointer_rtx +#endif +#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + || temp == hard_frame_pointer_rtx #endif - ) + || temp == frame_pointer_rtx) + return 1; + + if (GET_CODE (temp) == PLUS + && CONSTANT_ADDRESS_P (XEXP (temp, 1)) + && (XEXP (temp, 0) == frame_pointer_rtx +#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + || XEXP (temp, 0) == hard_frame_pointer_rtx +#endif +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + || XEXP (temp, 0) == arg_pointer_rtx +#endif + )) + return 1; + + if (temp == virtual_stack_vars_rtx + || temp == virtual_incoming_args_rtx + || (GET_CODE (temp) == PLUS + && CONSTANT_ADDRESS_P (XEXP (temp, 1)) + && (XEXP (temp, 0) == virtual_stack_vars_rtx + || XEXP (temp, 0) == virtual_incoming_args_rtx))) + { + /* This MEM may be shared. If the substitution can be done without + the need to generate new pseudos, we want to do it in place + so all copies of the shared rtx benefit. The call below will + only make substitutions if the resulting address is still + valid. + + Note that we cannot pass X as the object in the recursive call + since the insn being processed may not allow all valid + addresses. However, if we were not passed on object, we can + only modify X without copying it if X will have a valid + address. + + ??? Also note that this can still lose if OBJECT is an insn that + has less restrictions on an address that some other insn. + In that case, we will modify the shared address. This case + doesn't seem very likely, though. One case where this could + happen is in the case of a USE or CLOBBER reference, but we + take care of that below. */ + + if (instantiate_virtual_regs_1 (&XEXP (x, 0), + object ? object : x, 0)) + return 1; + + /* Otherwise make a copy and process that copy. We copy the entire + RTL expression since it might be a PLUS which could also be + shared. */ + *loc = x = copy_rtx (x); + } + + /* Fall through to generic unary operation case. */ + case PREFETCH: + case SUBREG: + case STRICT_LOW_PART: + case NEG: case NOT: + case PRE_DEC: case PRE_INC: case POST_DEC: case POST_INC: + case SIGN_EXTEND: case ZERO_EXTEND: + case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: + case FLOAT: case FIX: + case UNSIGNED_FIX: case UNSIGNED_FLOAT: + case ABS: + case SQRT: + case FFS: + case CLZ: case CTZ: + case POPCOUNT: case PARITY: + /* These case either have just one operand or we know that we need not + check the rest of the operands. */ + loc = &XEXP (x, 0); + goto restart; + + case USE: + case CLOBBER: + /* If the operand is a MEM, see if the change is a valid MEM. If not, + go ahead and make the invalid one, but do it to a copy. For a REG, + just make the recursive call, since there's no chance of a problem. */ + + if ((GET_CODE (XEXP (x, 0)) == MEM + && instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0), + 0)) + || (GET_CODE (XEXP (x, 0)) == REG + && instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0))) + return 1; + + XEXP (x, 0) = copy_rtx (XEXP (x, 0)); + loc = &XEXP (x, 0); + goto restart; + + case REG: + /* Try to replace with a PLUS. If that doesn't work, compute the sum + in front of this insn and substitute the temporary. */ + if ((new = instantiate_new_reg (x, &offset)) != 0) + { + temp = plus_constant (new, offset); + if (!validate_change (object, loc, temp, 0)) { - rtx tem, x; - int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT; - rtx reg = gen_rtx_REG (word_mode, REGNO (entry_parm)); - - x = expand_shift (LSHIFT_EXPR, word_mode, reg, - build_int_cst (NULL_TREE, by), - NULL_RTX, 1); - tem = change_address (mem, word_mode, 0); - emit_move_insn (tem, x); + if (! extra_insns) + return 0; + + start_sequence (); + temp = force_operand (temp, NULL_RTX); + seq = get_insns (); + end_sequence (); + + emit_insn_before (seq, object); + if (! validate_change (object, loc, temp, 0) + && ! validate_replace_rtx (x, temp, object)) + instantiate_virtual_regs_lossage (object); } - else - move_block_from_reg (REGNO (entry_parm), mem, - size_stored / UNITS_PER_WORD); } - else - move_block_from_reg (REGNO (entry_parm), mem, - size_stored / UNITS_PER_WORD); + + return 1; + + case ADDRESSOF: + if (GET_CODE (XEXP (x, 0)) == REG) + return 1; + + else if (GET_CODE (XEXP (x, 0)) == MEM) + { + /* If we have a (addressof (mem ..)), do any instantiation inside + since we know we'll be making the inside valid when we finally + remove the ADDRESSOF. */ + instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), NULL_RTX, 0); + return 1; + } + break; + + default: + break; } - else if (data->stack_parm == 0) + + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) + if (*fmt == 'e') + { + if (!instantiate_virtual_regs_1 (&XEXP (x, i), object, extra_insns)) + return 0; + } + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + if (! instantiate_virtual_regs_1 (&XVECEXP (x, i, j), object, + extra_insns)) + return 0; + + return 1; +} + +/* Optimization: assuming this function does not receive nonlocal gotos, + delete the handlers for such, as well as the insns to establish + and disestablish them. */ + +static void +delete_handlers (void) +{ + rtx insn; + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { - push_to_sequence (all->conversion_insns); - emit_block_move (stack_parm, data->entry_parm, GEN_INT (size), - BLOCK_OP_NORMAL); - all->conversion_insns = get_insns (); - end_sequence (); + /* Delete the handler by turning off the flag that would + prevent jump_optimize from deleting it. + Also permit deletion of the nonlocal labels themselves + if nothing local refers to them. */ + if (GET_CODE (insn) == CODE_LABEL) + { + tree t, last_t; + + LABEL_PRESERVE_P (insn) = 0; + + /* Remove it from the nonlocal_label list, to avoid confusing + flow. */ + for (t = nonlocal_labels, last_t = 0; t; + last_t = t, t = TREE_CHAIN (t)) + if (DECL_RTL (TREE_VALUE (t)) == insn) + break; + if (t) + { + if (! last_t) + nonlocal_labels = TREE_CHAIN (nonlocal_labels); + else + TREE_CHAIN (last_t) = TREE_CHAIN (t); + } + } + if (GET_CODE (insn) == INSN) + { + int can_delete = 0; + rtx t; + for (t = nonlocal_goto_handler_slots; t != 0; t = XEXP (t, 1)) + if (reg_mentioned_p (t, PATTERN (insn))) + { + can_delete = 1; + break; + } + if (can_delete + || (nonlocal_goto_stack_level != 0 + && reg_mentioned_p (nonlocal_goto_stack_level, + PATTERN (insn)))) + delete_related_insns (insn); + } } +} + +/* Return the first insn following those generated by `assign_parms'. */ - data->stack_parm = stack_parm; - SET_DECL_RTL (parm, stack_parm); +rtx +get_first_nonparm_insn (void) +{ + if (last_parm_insn) + return NEXT_INSN (last_parm_insn); + return get_insns (); } -/* A subroutine of assign_parms. Allocate a pseudo to hold the current - parameter. Get it there. Perform all ABI specified conversions. */ +/* Return 1 if EXP is an aggregate type (or a value with aggregate type). + This means a type for which function calls must pass an address to the + function or get an address back from the function. + EXP may be a type node or an expression (whose type is tested). */ -static void -assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm, - struct assign_parm_data_one *data) +int +aggregate_value_p (tree exp, tree fntype) +{ + int i, regno, nregs; + rtx reg; + + tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp); + + if (fntype) + switch (TREE_CODE (fntype)) + { + case CALL_EXPR: + fntype = get_callee_fndecl (fntype); + fntype = fntype ? TREE_TYPE (fntype) : 0; + break; + case FUNCTION_DECL: + fntype = TREE_TYPE (fntype); + break; + case FUNCTION_TYPE: + case METHOD_TYPE: + break; + case IDENTIFIER_NODE: + fntype = 0; + break; + default: + /* We don't expect other rtl types here. */ + abort(); + } + + if (TREE_CODE (type) == VOID_TYPE) + return 0; + if (targetm.calls.return_in_memory (type, fntype)) + return 1; + /* Types that are TREE_ADDRESSABLE must be constructed in memory, + and thus can't be returned in registers. */ + if (TREE_ADDRESSABLE (type)) + return 1; + if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type)) + return 1; + /* Make sure we have suitable call-clobbered regs to return + the value in; if not, we must return it in memory. */ + reg = hard_function_value (type, 0, 0); + + /* If we have something other than a REG (e.g. a PARALLEL), then assume + it is OK. */ + if (GET_CODE (reg) != REG) + return 0; + + regno = REGNO (reg); + nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type)); + for (i = 0; i < nregs; i++) + if (! call_used_regs[regno + i]) + return 1; + return 0; +} + +/* Assign RTL expressions to the function's parameters. + This may involve copying them into registers and using + those registers as the RTL for them. */ + +void +assign_parms (tree fndecl) { - rtx parmreg; - enum machine_mode promoted_nominal_mode; - int unsignedp = TYPE_UNSIGNED (TREE_TYPE (parm)); - bool did_conversion = false; + tree parm; + CUMULATIVE_ARGS args_so_far; + /* Total space needed so far for args on the stack, + given as a constant and a tree-expression. */ + struct args_size stack_args_size; + tree fntype = TREE_TYPE (fndecl); + tree fnargs = DECL_ARGUMENTS (fndecl), orig_fnargs; + /* This is used for the arg pointer when referring to stack args. */ + rtx internal_arg_pointer; + /* This is a dummy PARM_DECL that we used for the function result if + the function returns a structure. */ + tree function_result_decl = 0; + int varargs_setup = 0; + int reg_parm_stack_space ATTRIBUTE_UNUSED = 0; + rtx conversion_insns = 0; + + /* Nonzero if function takes extra anonymous args. + This means the last named arg must be on the stack + right before the anonymous ones. */ + int stdarg + = (TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + != void_type_node)); + + current_function_stdarg = stdarg; - /* Store the parm in a pseudoregister during the function, but we may - need to do it in a wider mode. */ + /* If the reg that the virtual arg pointer will be translated into is + not a fixed reg or is the stack pointer, make a copy of the virtual + arg pointer, and address parms via the copy. The frame pointer is + considered fixed even though it is not marked as such. - /* This is not really promoting for a call. However we need to be - consistent with assign_parm_find_data_types and expand_expr_real_1. */ - promoted_nominal_mode - = promote_mode (data->nominal_type, data->nominal_mode, &unsignedp, 1); + The second time through, simply use ap to avoid generating rtx. */ - parmreg = gen_reg_rtx (promoted_nominal_mode); + if ((ARG_POINTER_REGNUM == STACK_POINTER_REGNUM + || ! (fixed_regs[ARG_POINTER_REGNUM] + || ARG_POINTER_REGNUM == FRAME_POINTER_REGNUM))) + internal_arg_pointer = copy_to_reg (virtual_incoming_args_rtx); + else + internal_arg_pointer = virtual_incoming_args_rtx; + current_function_internal_arg_pointer = internal_arg_pointer; - if (!DECL_ARTIFICIAL (parm)) - mark_user_reg (parmreg); + stack_args_size.constant = 0; + stack_args_size.var = 0; - /* If this was an item that we received a pointer to, - set DECL_RTL appropriately. */ - if (data->passed_pointer) + /* If struct value address is treated as the first argument, make it so. */ + if (aggregate_value_p (DECL_RESULT (fndecl), fndecl) + && ! current_function_returns_pcc_struct + && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0) { - rtx x = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data->passed_type)), parmreg); - set_mem_attributes (x, parm, 1); - SET_DECL_RTL (parm, x); + tree type = build_pointer_type (TREE_TYPE (fntype)); + + function_result_decl = build_decl (PARM_DECL, NULL_TREE, type); + + DECL_ARG_TYPE (function_result_decl) = type; + TREE_CHAIN (function_result_decl) = fnargs; + fnargs = function_result_decl; } - else - SET_DECL_RTL (parm, parmreg); - /* Copy the value into the register. */ - if (data->nominal_mode != data->passed_mode - || promoted_nominal_mode != data->promoted_mode) + orig_fnargs = fnargs; + + max_parm_reg = LAST_VIRTUAL_REGISTER + 1; + parm_reg_stack_loc = ggc_alloc_cleared (max_parm_reg * sizeof (rtx)); + + /* If the target wants to split complex arguments into scalars, do so. */ + if (targetm.calls.split_complex_arg) + fnargs = split_complex_args (fnargs); + +#ifdef REG_PARM_STACK_SPACE +#ifdef MAYBE_REG_PARM_STACK_SPACE + reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE; +#else + reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl); +#endif +#endif + +#ifdef INIT_CUMULATIVE_INCOMING_ARGS + INIT_CUMULATIVE_INCOMING_ARGS (args_so_far, fntype, NULL_RTX); +#else + INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, fndecl, -1); +#endif + + /* We haven't yet found an argument that we must push and pretend the + caller did. */ + current_function_pretend_args_size = 0; + + for (parm = fnargs; parm; parm = TREE_CHAIN (parm)) { - int save_tree_used; - - /* ENTRY_PARM has been converted to PROMOTED_MODE, its - mode, by the caller. We now have to convert it to - NOMINAL_MODE, if different. However, PARMREG may be in - a different mode than NOMINAL_MODE if it is being stored - promoted. - - If ENTRY_PARM is a hard register, it might be in a register - not valid for operating in its mode (e.g., an odd-numbered - register for a DFmode). In that case, moves are the only - thing valid, so we can't do a convert from there. This - occurs when the calling sequence allow such misaligned - usages. - - In addition, the conversion may involve a call, which could - clobber parameters which haven't been copied to pseudo - registers yet. Therefore, we must first copy the parm to - a pseudo reg here, and save the conversion until after all - parameters have been moved. */ - - rtx tempreg = gen_reg_rtx (GET_MODE (data->entry_parm)); - - emit_move_insn (tempreg, validize_mem (data->entry_parm)); - - push_to_sequence (all->conversion_insns); - tempreg = convert_to_mode (data->nominal_mode, tempreg, unsignedp); - - if (GET_CODE (tempreg) == SUBREG - && GET_MODE (tempreg) == data->nominal_mode - && REG_P (SUBREG_REG (tempreg)) - && data->nominal_mode == data->passed_mode - && GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (data->entry_parm) - && GET_MODE_SIZE (GET_MODE (tempreg)) - < GET_MODE_SIZE (GET_MODE (data->entry_parm))) + rtx entry_parm; + rtx stack_parm; + enum machine_mode promoted_mode, passed_mode; + enum machine_mode nominal_mode, promoted_nominal_mode; + int unsignedp; + struct locate_and_pad_arg_data locate; + int passed_pointer = 0; + int did_conversion = 0; + tree passed_type = DECL_ARG_TYPE (parm); + tree nominal_type = TREE_TYPE (parm); + int last_named = 0, named_arg; + int in_regs; + int partial = 0; + int pretend_bytes = 0; + + /* Set LAST_NAMED if this is last named arg before last + anonymous args. */ + if (stdarg) { - /* The argument is already sign/zero extended, so note it - into the subreg. */ - SUBREG_PROMOTED_VAR_P (tempreg) = 1; - SUBREG_PROMOTED_UNSIGNED_SET (tempreg, unsignedp); + tree tem; + + for (tem = TREE_CHAIN (parm); tem; tem = TREE_CHAIN (tem)) + if (DECL_NAME (tem)) + break; + + if (tem == 0) + last_named = 1; + } + /* Set NAMED_ARG if this arg should be treated as a named arg. For + most machines, if this is a varargs/stdarg function, then we treat + the last named arg as if it were anonymous too. */ + named_arg = targetm.calls.strict_argument_naming (&args_so_far) ? 1 : ! last_named; + + if (TREE_TYPE (parm) == error_mark_node + /* This can happen after weird syntax errors + or if an enum type is defined among the parms. */ + || TREE_CODE (parm) != PARM_DECL + || passed_type == NULL) + { + SET_DECL_RTL (parm, gen_rtx_MEM (BLKmode, const0_rtx)); + DECL_INCOMING_RTL (parm) = DECL_RTL (parm); + TREE_USED (parm) = 1; + continue; } - /* TREE_USED gets set erroneously during expand_assignment. */ - save_tree_used = TREE_USED (parm); - expand_assignment (parm, make_tree (data->nominal_type, tempreg)); - TREE_USED (parm) = save_tree_used; - all->conversion_insns = get_insns (); - end_sequence (); + /* Find mode of arg as it is passed, and mode of arg + as it should be during execution of this function. */ + passed_mode = TYPE_MODE (passed_type); + nominal_mode = TYPE_MODE (nominal_type); - did_conversion = true; - } - else - emit_move_insn (parmreg, validize_mem (data->entry_parm)); - - /* If we were passed a pointer but the actual value can safely live - in a register, put it in one. */ - if (data->passed_pointer - && TYPE_MODE (TREE_TYPE (parm)) != BLKmode - /* If by-reference argument was promoted, demote it. */ - && (TYPE_MODE (TREE_TYPE (parm)) != GET_MODE (DECL_RTL (parm)) - || use_register_for_decl (parm))) - { - /* We can't use nominal_mode, because it will have been set to - Pmode above. We must use the actual mode of the parm. */ - parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm))); - mark_user_reg (parmreg); + /* If the parm's mode is VOID, its value doesn't matter, + and avoid the usual things like emit_move_insn that could crash. */ + if (nominal_mode == VOIDmode) + { + SET_DECL_RTL (parm, const0_rtx); + DECL_INCOMING_RTL (parm) = DECL_RTL (parm); + continue; + } - if (GET_MODE (parmreg) != GET_MODE (DECL_RTL (parm))) + /* If the parm is to be passed as a transparent union, use the + type of the first field for the tests below. We have already + verified that the modes are the same. */ + if (DECL_TRANSPARENT_UNION (parm) + || (TREE_CODE (passed_type) == UNION_TYPE + && TYPE_TRANSPARENT_UNION (passed_type))) + passed_type = TREE_TYPE (TYPE_FIELDS (passed_type)); + + /* See if this arg was passed by invisible reference. It is if + it is an object whose size depends on the contents of the + object itself or if the machine requires these objects be passed + that way. */ + + if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (passed_type)) + || TREE_ADDRESSABLE (passed_type) +#ifdef FUNCTION_ARG_PASS_BY_REFERENCE + || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode, + passed_type, named_arg) +#endif + ) { - rtx tempreg = gen_reg_rtx (GET_MODE (DECL_RTL (parm))); - int unsigned_p = TYPE_UNSIGNED (TREE_TYPE (parm)); - - push_to_sequence (all->conversion_insns); - emit_move_insn (tempreg, DECL_RTL (parm)); - tempreg = convert_to_mode (GET_MODE (parmreg), tempreg, unsigned_p); - emit_move_insn (parmreg, tempreg); - all->conversion_insns = get_insns (); - end_sequence (); + passed_type = nominal_type = build_pointer_type (passed_type); + passed_pointer = 1; + passed_mode = nominal_mode = Pmode; + } + /* See if the frontend wants to pass this by invisible reference. */ + else if (passed_type != nominal_type + && POINTER_TYPE_P (passed_type) + && TREE_TYPE (passed_type) == nominal_type) + { + nominal_type = passed_type; + passed_pointer = 1; + passed_mode = nominal_mode = Pmode; + } - did_conversion = true; + promoted_mode = passed_mode; + + if (targetm.calls.promote_function_args (TREE_TYPE (fndecl))) + { + /* Compute the mode in which the arg is actually extended to. */ + unsignedp = TREE_UNSIGNED (passed_type); + promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1); } - else - emit_move_insn (parmreg, DECL_RTL (parm)); - SET_DECL_RTL (parm, parmreg); + /* Let machine desc say which reg (if any) the parm arrives in. + 0 means it arrives on the stack. */ +#ifdef FUNCTION_INCOMING_ARG + entry_parm = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode, + passed_type, named_arg); +#else + entry_parm = FUNCTION_ARG (args_so_far, promoted_mode, + passed_type, named_arg); +#endif + + if (entry_parm == 0) + promoted_mode = passed_mode; - /* STACK_PARM is the pointer, not the parm, and PARMREG is - now the parm. */ - data->stack_parm = NULL; - } + /* If this is the last named parameter, do any required setup for + varargs or stdargs. We need to know about the case of this being an + addressable type, in which case we skip the registers it + would have arrived in. - /* Mark the register as eliminable if we did no conversion and it was - copied from memory at a fixed offset, and the arg pointer was not - copied to a pseudo-reg. If the arg pointer is a pseudo reg or the - offset formed an invalid address, such memory-equivalences as we - make here would screw up life analysis for it. */ - if (data->nominal_mode == data->passed_mode - && !did_conversion - && data->stack_parm != 0 - && MEM_P (data->stack_parm) - && data->locate.offset.var == 0 - && reg_mentioned_p (virtual_incoming_args_rtx, - XEXP (data->stack_parm, 0))) - { - rtx linsn = get_last_insn (); - rtx sinsn, set; + For stdargs, LAST_NAMED will be set for two parameters, the one that + is actually the last named, and the dummy parameter. We only + want to do this action once. + + Also, indicate when RTL generation is to be suppressed. */ + if (last_named && !varargs_setup) + { + int varargs_pretend_bytes = 0; + targetm.calls.setup_incoming_varargs (&args_so_far, promoted_mode, + passed_type, + &varargs_pretend_bytes, 0); + varargs_setup = 1; + + /* If the back-end has requested extra stack space, record how + much is needed. Do not change pretend_args_size otherwise + since it may be nonzero from an earlier partial argument. */ + if (varargs_pretend_bytes > 0) + current_function_pretend_args_size = varargs_pretend_bytes; + } + + /* Determine parm's home in the stack, + in case it arrives in the stack or we should pretend it did. + + Compute the stack position and rtx where the argument arrives + and its size. - /* Mark complex types separately. */ - if (GET_CODE (parmreg) == CONCAT) + There is one complexity here: If this was a parameter that would + have been passed in registers, but wasn't only because it is + __builtin_va_alist, we want locate_and_pad_parm to treat it as if + it came in a register so that REG_PARM_STACK_SPACE isn't skipped. + In this case, we call FUNCTION_ARG with NAMED set to 1 instead of + 0 as it was the previous time. */ + in_regs = entry_parm != 0; +#ifdef STACK_PARMS_IN_REG_PARM_AREA + in_regs = 1; +#endif + if (!in_regs && !named_arg) { - enum machine_mode submode - = GET_MODE_INNER (GET_MODE (parmreg)); - int regnor = REGNO (XEXP (parmreg, 0)); - int regnoi = REGNO (XEXP (parmreg, 1)); - rtx stackr = adjust_address_nv (data->stack_parm, submode, 0); - rtx stacki = adjust_address_nv (data->stack_parm, submode, - GET_MODE_SIZE (submode)); - - /* Scan backwards for the set of the real and - imaginary parts. */ - for (sinsn = linsn; sinsn != 0; - sinsn = prev_nonnote_insn (sinsn)) + int pretend_named = + targetm.calls.pretend_outgoing_varargs_named (&args_so_far); + if (pretend_named) { - set = single_set (sinsn); - if (set == 0) - continue; +#ifdef FUNCTION_INCOMING_ARG + in_regs = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode, + passed_type, + pretend_named) != 0; +#else + in_regs = FUNCTION_ARG (args_so_far, promoted_mode, + passed_type, + pretend_named) != 0; +#endif + } + } - if (SET_DEST (set) == regno_reg_rtx [regnoi]) - REG_NOTES (sinsn) - = gen_rtx_EXPR_LIST (REG_EQUIV, stacki, - REG_NOTES (sinsn)); - else if (SET_DEST (set) == regno_reg_rtx [regnor]) - REG_NOTES (sinsn) - = gen_rtx_EXPR_LIST (REG_EQUIV, stackr, - REG_NOTES (sinsn)); + /* If this parameter was passed both in registers and in the stack, + use the copy on the stack. */ + if (MUST_PASS_IN_STACK (promoted_mode, passed_type)) + entry_parm = 0; + +#ifdef FUNCTION_ARG_PARTIAL_NREGS + if (entry_parm) + { + partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode, + passed_type, named_arg); + if (partial +#ifndef MAYBE_REG_PARM_STACK_SPACE + /* The caller might already have allocated stack space + for the register parameters. */ + && reg_parm_stack_space == 0 +#endif + ) + { + /* Part of this argument is passed in registers and part + is passed on the stack. Ask the prologue code to extend + the stack part so that we can recreate the full value. + + PRETEND_BYTES is the size of the registers we need to store. + CURRENT_FUNCTION_PRETEND_ARGS_SIZE is the amount of extra + stack space that the prologue should allocate. + + Internally, gcc assumes that the argument pointer is + aligned to STACK_BOUNDARY bits. This is used both for + alignment optimizations (see init_emit) and to locate + arguments that are aligned to more than PARM_BOUNDARY + bits. We must preserve this invariant by rounding + CURRENT_FUNCTION_PRETEND_ARGS_SIZE up to a stack + boundary. */ + pretend_bytes = partial * UNITS_PER_WORD; + current_function_pretend_args_size + = CEIL_ROUND (pretend_bytes, STACK_BYTES); + + /* If PRETEND_BYTES != CURRENT_FUNCTION_PRETEND_ARGS_SIZE, + insert the padding before the start of the first pretend + argument. */ + stack_args_size.constant + = (current_function_pretend_args_size - pretend_bytes); } } - else if ((set = single_set (linsn)) != 0 - && SET_DEST (set) == parmreg) - REG_NOTES (linsn) - = gen_rtx_EXPR_LIST (REG_EQUIV, - data->stack_parm, REG_NOTES (linsn)); - } +#endif - /* For pointer data type, suggest pointer register. */ - if (POINTER_TYPE_P (TREE_TYPE (parm))) - mark_reg_pointer (parmreg, - TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm)))); -} + memset (&locate, 0, sizeof (locate)); + locate_and_pad_parm (promoted_mode, passed_type, in_regs, + entry_parm ? partial : 0, fndecl, + &stack_args_size, &locate); -/* A subroutine of assign_parms. Allocate stack space to hold the current - parameter. Get it there. Perform all ABI specified conversions. */ + { + rtx offset_rtx; + unsigned int align, boundary; + + /* If we're passing this arg using a reg, make its stack home + the aligned stack slot. */ + if (entry_parm) + offset_rtx = ARGS_SIZE_RTX (locate.slot_offset); + else + offset_rtx = ARGS_SIZE_RTX (locate.offset); + + if (offset_rtx == const0_rtx) + stack_parm = gen_rtx_MEM (promoted_mode, internal_arg_pointer); + else + stack_parm = gen_rtx_MEM (promoted_mode, + gen_rtx_PLUS (Pmode, + internal_arg_pointer, + offset_rtx)); + + set_mem_attributes (stack_parm, parm, 1); + + boundary = FUNCTION_ARG_BOUNDARY (promoted_mode, passed_type); + align = 0; + + /* If we're padding upward, we know that the alignment of the slot + is FUNCTION_ARG_BOUNDARY. If we're using slot_offset, we're + intentionally forcing upward padding. Otherwise we have to come + up with a guess at the alignment based on OFFSET_RTX. */ + if (locate.where_pad == upward || entry_parm) + align = boundary; + else if (GET_CODE (offset_rtx) == CONST_INT) + { + align = INTVAL (offset_rtx) * BITS_PER_UNIT | boundary; + align = align & -align; + } + if (align > 0) + set_mem_align (stack_parm, align); -static void -assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm, - struct assign_parm_data_one *data) -{ - /* Value must be stored in the stack slot STACK_PARM during function - execution. */ - bool to_conversion = false; + if (entry_parm) + set_reg_attrs_for_parm (entry_parm, stack_parm); + } - if (data->promoted_mode != data->nominal_mode) - { - /* Conversion is required. */ - rtx tempreg = gen_reg_rtx (GET_MODE (data->entry_parm)); + /* If this parm was passed part in regs and part in memory, + pretend it arrived entirely in memory + by pushing the register-part onto the stack. - emit_move_insn (tempreg, validize_mem (data->entry_parm)); + In the special case of a DImode or DFmode that is split, + we could put it together in a pseudoreg directly, + but for now that's not worth bothering with. */ - push_to_sequence (all->conversion_insns); - to_conversion = true; + if (partial) + { + /* Handle calls that pass values in multiple non-contiguous + locations. The Irix 6 ABI has examples of this. */ + if (GET_CODE (entry_parm) == PARALLEL) + emit_group_store (validize_mem (stack_parm), entry_parm, + TREE_TYPE (parm), + int_size_in_bytes (TREE_TYPE (parm))); - data->entry_parm = convert_to_mode (data->nominal_mode, tempreg, - TYPE_UNSIGNED (TREE_TYPE (parm))); + else + move_block_from_reg (REGNO (entry_parm), validize_mem (stack_parm), + partial); - if (data->stack_parm) - /* ??? This may need a big-endian conversion on sparc64. */ - data->stack_parm - = adjust_address (data->stack_parm, data->nominal_mode, 0); - } + entry_parm = stack_parm; + } - if (data->entry_parm != data->stack_parm) - { - rtx src, dest; + /* If we didn't decide this parm came in a register, + by default it came on the stack. */ + if (entry_parm == 0) + entry_parm = stack_parm; - if (data->stack_parm == 0) + /* Record permanently how this parm was passed. */ + DECL_INCOMING_RTL (parm) = entry_parm; + + /* If there is actually space on the stack for this parm, + count it in stack_args_size; otherwise set stack_parm to 0 + to indicate there is no preallocated stack slot for the parm. */ + + if (entry_parm == stack_parm + || (GET_CODE (entry_parm) == PARALLEL + && XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX) +#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE) + /* On some machines, even if a parm value arrives in a register + there is still an (uninitialized) stack slot allocated for it. + + ??? When MAYBE_REG_PARM_STACK_SPACE is defined, we can't tell + whether this parameter already has a stack slot allocated, + because an arg block exists only if current_function_args_size + is larger than some threshold, and we haven't calculated that + yet. So, for now, we just assume that stack slots never exist + in this case. */ + || REG_PARM_STACK_SPACE (fndecl) > 0 +#endif + ) { - data->stack_parm - = assign_stack_local (GET_MODE (data->entry_parm), - GET_MODE_SIZE (GET_MODE (data->entry_parm)), - TYPE_ALIGN (data->passed_type)); - set_mem_attributes (data->stack_parm, parm, 1); + stack_args_size.constant += pretend_bytes + locate.size.constant; + if (locate.size.var) + ADD_PARM_SIZE (stack_args_size, locate.size.var); } + else + /* No stack slot was pushed for this parm. */ + stack_parm = 0; - dest = validize_mem (data->stack_parm); - src = validize_mem (data->entry_parm); + /* Update info on where next arg arrives in registers. */ - if (MEM_P (src)) + FUNCTION_ARG_ADVANCE (args_so_far, promoted_mode, + passed_type, named_arg); + + /* If we can't trust the parm stack slot to be aligned enough + for its ultimate type, don't use that slot after entry. + We'll make another stack slot, if we need one. */ + if (STRICT_ALIGNMENT && stack_parm + && GET_MODE_ALIGNMENT (nominal_mode) > MEM_ALIGN (stack_parm)) + stack_parm = 0; + + /* If parm was passed in memory, and we need to convert it on entry, + don't store it back in that same slot. */ + if (entry_parm == stack_parm + && nominal_mode != BLKmode && nominal_mode != passed_mode) + stack_parm = 0; + + /* When an argument is passed in multiple locations, we can't + make use of this information, but we can save some copying if + the whole argument is passed in a single register. */ + if (GET_CODE (entry_parm) == PARALLEL + && nominal_mode != BLKmode && passed_mode != BLKmode) { - /* Use a block move to handle potentially misaligned entry_parm. */ - if (!to_conversion) - push_to_sequence (all->conversion_insns); - to_conversion = true; - - emit_block_move (dest, src, - GEN_INT (int_size_in_bytes (data->passed_type)), - BLOCK_OP_NORMAL); + int i, len = XVECLEN (entry_parm, 0); + + for (i = 0; i < len; i++) + if (XEXP (XVECEXP (entry_parm, 0, i), 0) != NULL_RTX + && GET_CODE (XEXP (XVECEXP (entry_parm, 0, i), 0)) == REG + && (GET_MODE (XEXP (XVECEXP (entry_parm, 0, i), 0)) + == passed_mode) + && INTVAL (XEXP (XVECEXP (entry_parm, 0, i), 1)) == 0) + { + entry_parm = XEXP (XVECEXP (entry_parm, 0, i), 0); + DECL_INCOMING_RTL (parm) = entry_parm; + break; + } } - else - emit_move_insn (dest, src); - } - if (to_conversion) - { - all->conversion_insns = get_insns (); - end_sequence (); - } + /* ENTRY_PARM is an RTX for the parameter as it arrives, + in the mode in which it arrives. + STACK_PARM is an RTX for a stack slot where the parameter can live + during the function (in case we want to put it there). + STACK_PARM is 0 if no stack slot was pushed for it. - SET_DECL_RTL (parm, data->stack_parm); -} + Now output code if necessary to convert ENTRY_PARM to + the type in which this function declares it, + and store that result in an appropriate place, + which may be a pseudo reg, may be STACK_PARM, + or may be a local stack slot if STACK_PARM is 0. -/* A subroutine of assign_parms. If the ABI splits complex arguments, then - undo the frobbing that we did in assign_parms_augmented_arg_list. */ + Set DECL_RTL to that place. */ -static void -assign_parms_unsplit_complex (struct assign_parm_data_all *all, tree fnargs) -{ - tree parm; - tree orig_fnargs = all->orig_fnargs; + if (GET_CODE (entry_parm) == PARALLEL && nominal_mode != BLKmode + && XVECLEN (entry_parm, 0) > 1) + { + /* Reconstitute objects the size of a register or larger using + register operations instead of the stack. */ + rtx parmreg = gen_reg_rtx (nominal_mode); - for (parm = orig_fnargs; parm; parm = TREE_CHAIN (parm)) - { - if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE - && targetm.calls.split_complex_arg (TREE_TYPE (parm))) + if (REG_P (parmreg)) + { + unsigned int regno = REGNO (parmreg); + + emit_group_store (parmreg, entry_parm, TREE_TYPE (parm), + int_size_in_bytes (TREE_TYPE (parm))); + SET_DECL_RTL (parm, parmreg); + + if (regno >= max_parm_reg) + { + rtx *new; + int old_max_parm_reg = max_parm_reg; + + /* It's slow to expand this one register at a time, + but it's also rare and we need max_parm_reg to be + precisely correct. */ + max_parm_reg = regno + 1; + new = ggc_realloc (parm_reg_stack_loc, + max_parm_reg * sizeof (rtx)); + memset (new + old_max_parm_reg, 0, + (max_parm_reg - old_max_parm_reg) * sizeof (rtx)); + parm_reg_stack_loc = new; + parm_reg_stack_loc[regno] = stack_parm; + } + } + } + + if (nominal_mode == BLKmode +#ifdef BLOCK_REG_PADDING + || (locate.where_pad == (BYTES_BIG_ENDIAN ? upward : downward) + && GET_MODE_SIZE (promoted_mode) < UNITS_PER_WORD) +#endif + || GET_CODE (entry_parm) == PARALLEL) + { + /* If a BLKmode arrives in registers, copy it to a stack slot. + Handle calls that pass values in multiple non-contiguous + locations. The Irix 6 ABI has examples of this. */ + if (GET_CODE (entry_parm) == REG + || GET_CODE (entry_parm) == PARALLEL) + { + int size = int_size_in_bytes (TREE_TYPE (parm)); + int size_stored = CEIL_ROUND (size, UNITS_PER_WORD); + rtx mem; + + /* Note that we will be storing an integral number of words. + So we have to be careful to ensure that we allocate an + integral number of words. We do this below in the + assign_stack_local if space was not allocated in the argument + list. If it was, this will not work if PARM_BOUNDARY is not + a multiple of BITS_PER_WORD. It isn't clear how to fix this + if it becomes a problem. Exception is when BLKmode arrives + with arguments not conforming to word_mode. */ + + if (stack_parm == 0) + { + stack_parm = assign_stack_local (BLKmode, size_stored, 0); + PUT_MODE (stack_parm, GET_MODE (entry_parm)); + set_mem_attributes (stack_parm, parm, 1); + } + else if (GET_CODE (entry_parm) == PARALLEL) + ; + else if (PARM_BOUNDARY % BITS_PER_WORD != 0) + abort (); + + mem = validize_mem (stack_parm); + + /* Handle calls that pass values in multiple non-contiguous + locations. The Irix 6 ABI has examples of this. */ + if (GET_CODE (entry_parm) == PARALLEL) + emit_group_store (mem, entry_parm, TREE_TYPE (parm), size); + + else if (size == 0) + ; + + /* If SIZE is that of a mode no bigger than a word, just use + that mode's store operation. */ + else if (size <= UNITS_PER_WORD) + { + enum machine_mode mode + = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0); + + if (mode != BLKmode +#ifdef BLOCK_REG_PADDING + && (size == UNITS_PER_WORD + || (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1) + != (BYTES_BIG_ENDIAN ? upward : downward))) +#endif + ) + { + rtx reg = gen_rtx_REG (mode, REGNO (entry_parm)); + emit_move_insn (change_address (mem, mode, 0), reg); + } + + /* Blocks smaller than a word on a BYTES_BIG_ENDIAN + machine must be aligned to the left before storing + to memory. Note that the previous test doesn't + handle all cases (e.g. SIZE == 3). */ + else if (size != UNITS_PER_WORD +#ifdef BLOCK_REG_PADDING + && (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1) + == downward) +#else + && BYTES_BIG_ENDIAN +#endif + ) + { + rtx tem, x; + int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT; + rtx reg = gen_rtx_REG (word_mode, REGNO (entry_parm)); + + x = expand_binop (word_mode, ashl_optab, reg, + GEN_INT (by), 0, 1, OPTAB_WIDEN); + tem = change_address (mem, word_mode, 0); + emit_move_insn (tem, x); + } + else + move_block_from_reg (REGNO (entry_parm), mem, + size_stored / UNITS_PER_WORD); + } + else + move_block_from_reg (REGNO (entry_parm), mem, + size_stored / UNITS_PER_WORD); + } + /* If parm is already bound to register pair, don't change + this binding. */ + if (! DECL_RTL_SET_P (parm)) + SET_DECL_RTL (parm, stack_parm); + } + else if (! ((! optimize + && ! DECL_REGISTER (parm)) + || TREE_SIDE_EFFECTS (parm) + /* If -ffloat-store specified, don't put explicit + float variables into registers. */ + || (flag_float_store + && TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE)) + /* Always assign pseudo to structure return or item passed + by invisible reference. */ + || passed_pointer || parm == function_result_decl) { - rtx tmp, real, imag; - enum machine_mode inner = GET_MODE_INNER (DECL_MODE (parm)); + /* Store the parm in a pseudoregister during the function, but we + may need to do it in a wider mode. */ - real = DECL_RTL (fnargs); - imag = DECL_RTL (TREE_CHAIN (fnargs)); - if (inner != GET_MODE (real)) + rtx parmreg; + unsigned int regno, regnoi = 0, regnor = 0; + + unsignedp = TREE_UNSIGNED (TREE_TYPE (parm)); + + promoted_nominal_mode + = promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0); + + parmreg = gen_reg_rtx (promoted_nominal_mode); + mark_user_reg (parmreg); + + /* If this was an item that we received a pointer to, set DECL_RTL + appropriately. */ + if (passed_pointer) { - real = gen_lowpart_SUBREG (inner, real); - imag = gen_lowpart_SUBREG (inner, imag); + rtx x = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), + parmreg); + set_mem_attributes (x, parm, 1); + SET_DECL_RTL (parm, x); + } + else + { + SET_DECL_RTL (parm, parmreg); + maybe_set_unchanging (DECL_RTL (parm), parm); } - if (TREE_ADDRESSABLE (parm)) + /* Copy the value into the register. */ + if (nominal_mode != passed_mode + || promoted_nominal_mode != promoted_mode) { - rtx rmem, imem; - HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (parm)); - - /* split_complex_arg put the real and imag parts in - pseudos. Move them to memory. */ - tmp = assign_stack_local (DECL_MODE (parm), size, - TYPE_ALIGN (TREE_TYPE (parm))); - set_mem_attributes (tmp, parm, 1); - rmem = adjust_address_nv (tmp, inner, 0); - imem = adjust_address_nv (tmp, inner, GET_MODE_SIZE (inner)); - push_to_sequence (all->conversion_insns); - emit_move_insn (rmem, real); - emit_move_insn (imem, imag); - all->conversion_insns = get_insns (); + int save_tree_used; + /* ENTRY_PARM has been converted to PROMOTED_MODE, its + mode, by the caller. We now have to convert it to + NOMINAL_MODE, if different. However, PARMREG may be in + a different mode than NOMINAL_MODE if it is being stored + promoted. + + If ENTRY_PARM is a hard register, it might be in a register + not valid for operating in its mode (e.g., an odd-numbered + register for a DFmode). In that case, moves are the only + thing valid, so we can't do a convert from there. This + occurs when the calling sequence allow such misaligned + usages. + + In addition, the conversion may involve a call, which could + clobber parameters which haven't been copied to pseudo + registers yet. Therefore, we must first copy the parm to + a pseudo reg here, and save the conversion until after all + parameters have been moved. */ + + rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm)); + + emit_move_insn (tempreg, validize_mem (entry_parm)); + + push_to_sequence (conversion_insns); + tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp); + + if (GET_CODE (tempreg) == SUBREG + && GET_MODE (tempreg) == nominal_mode + && GET_CODE (SUBREG_REG (tempreg)) == REG + && nominal_mode == passed_mode + && GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (entry_parm) + && GET_MODE_SIZE (GET_MODE (tempreg)) + < GET_MODE_SIZE (GET_MODE (entry_parm))) + { + /* The argument is already sign/zero extended, so note it + into the subreg. */ + SUBREG_PROMOTED_VAR_P (tempreg) = 1; + SUBREG_PROMOTED_UNSIGNED_SET (tempreg, unsignedp); + } + + /* TREE_USED gets set erroneously during expand_assignment. */ + save_tree_used = TREE_USED (parm); + expand_assignment (parm, + make_tree (nominal_type, tempreg), 0); + TREE_USED (parm) = save_tree_used; + conversion_insns = get_insns (); + did_conversion = 1; end_sequence (); } else - tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag); - SET_DECL_RTL (parm, tmp); - - real = DECL_INCOMING_RTL (fnargs); - imag = DECL_INCOMING_RTL (TREE_CHAIN (fnargs)); - if (inner != GET_MODE (real)) + emit_move_insn (parmreg, validize_mem (entry_parm)); + + /* If we were passed a pointer but the actual value + can safely live in a register, put it in one. */ + if (passed_pointer && TYPE_MODE (TREE_TYPE (parm)) != BLKmode + /* If by-reference argument was promoted, demote it. */ + && (TYPE_MODE (TREE_TYPE (parm)) != GET_MODE (DECL_RTL (parm)) + || ! ((! optimize + && ! DECL_REGISTER (parm)) + || TREE_SIDE_EFFECTS (parm) + /* If -ffloat-store specified, don't put explicit + float variables into registers. */ + || (flag_float_store + && TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE)))) { - real = gen_lowpart_SUBREG (inner, real); - imag = gen_lowpart_SUBREG (inner, imag); + /* We can't use nominal_mode, because it will have been set to + Pmode above. We must use the actual mode of the parm. */ + parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm))); + mark_user_reg (parmreg); + if (GET_MODE (parmreg) != GET_MODE (DECL_RTL (parm))) + { + rtx tempreg = gen_reg_rtx (GET_MODE (DECL_RTL (parm))); + int unsigned_p = TREE_UNSIGNED (TREE_TYPE (parm)); + push_to_sequence (conversion_insns); + emit_move_insn (tempreg, DECL_RTL (parm)); + SET_DECL_RTL (parm, + convert_to_mode (GET_MODE (parmreg), + tempreg, + unsigned_p)); + emit_move_insn (parmreg, DECL_RTL (parm)); + conversion_insns = get_insns(); + did_conversion = 1; + end_sequence (); + } + else + emit_move_insn (parmreg, DECL_RTL (parm)); + SET_DECL_RTL (parm, parmreg); + /* STACK_PARM is the pointer, not the parm, and PARMREG is + now the parm. */ + stack_parm = 0; } - tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag); - set_decl_incoming_rtl (parm, tmp); - fnargs = TREE_CHAIN (fnargs); - } - else - { - SET_DECL_RTL (parm, DECL_RTL (fnargs)); - set_decl_incoming_rtl (parm, DECL_INCOMING_RTL (fnargs)); +#ifdef FUNCTION_ARG_CALLEE_COPIES + /* If we are passed an arg by reference and it is our responsibility + to make a copy, do it now. + PASSED_TYPE and PASSED mode now refer to the pointer, not the + original argument, so we must recreate them in the call to + FUNCTION_ARG_CALLEE_COPIES. */ + /* ??? Later add code to handle the case that if the argument isn't + modified, don't do the copy. */ + + else if (passed_pointer + && FUNCTION_ARG_CALLEE_COPIES (args_so_far, + TYPE_MODE (TREE_TYPE (passed_type)), + TREE_TYPE (passed_type), + named_arg) + && ! TREE_ADDRESSABLE (TREE_TYPE (passed_type))) + { + rtx copy; + tree type = TREE_TYPE (passed_type); - /* Set MEM_EXPR to the original decl, i.e. to PARM, - instead of the copy of decl, i.e. FNARGS. */ - if (DECL_INCOMING_RTL (parm) && MEM_P (DECL_INCOMING_RTL (parm))) - set_mem_expr (DECL_INCOMING_RTL (parm), parm); - } + /* This sequence may involve a library call perhaps clobbering + registers that haven't been copied to pseudos yet. */ - fnargs = TREE_CHAIN (fnargs); - } -} + push_to_sequence (conversion_insns); -/* Assign RTL expressions to the function's parameters. This may involve - copying them into registers and using those registers as the DECL_RTL. */ + if (!COMPLETE_TYPE_P (type) + || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + /* This is a variable sized object. */ + copy = gen_rtx_MEM (BLKmode, + allocate_dynamic_stack_space + (expr_size (parm), NULL_RTX, + TYPE_ALIGN (type))); + else + copy = assign_stack_temp (TYPE_MODE (type), + int_size_in_bytes (type), 1); + set_mem_attributes (copy, parm, 1); + + store_expr (parm, copy, 0); + emit_move_insn (parmreg, XEXP (copy, 0)); + conversion_insns = get_insns (); + did_conversion = 1; + end_sequence (); + } +#endif /* FUNCTION_ARG_CALLEE_COPIES */ -static void -assign_parms (tree fndecl) -{ - struct assign_parm_data_all all; - tree fnargs, parm; + /* In any case, record the parm's desired stack location + in case we later discover it must live in the stack. - current_function_internal_arg_pointer - = targetm.calls.internal_arg_pointer (); + If it is a COMPLEX value, store the stack location for both + halves. */ - assign_parms_initialize_all (&all); - fnargs = assign_parms_augmented_arg_list (&all); + if (GET_CODE (parmreg) == CONCAT) + regno = MAX (REGNO (XEXP (parmreg, 0)), REGNO (XEXP (parmreg, 1))); + else + regno = REGNO (parmreg); - for (parm = fnargs; parm; parm = TREE_CHAIN (parm)) - { - struct assign_parm_data_one data; + if (regno >= max_parm_reg) + { + rtx *new; + int old_max_parm_reg = max_parm_reg; + + /* It's slow to expand this one register at a time, + but it's also rare and we need max_parm_reg to be + precisely correct. */ + max_parm_reg = regno + 1; + new = ggc_realloc (parm_reg_stack_loc, + max_parm_reg * sizeof (rtx)); + memset (new + old_max_parm_reg, 0, + (max_parm_reg - old_max_parm_reg) * sizeof (rtx)); + parm_reg_stack_loc = new; + } - /* Extract the type of PARM; adjust it according to ABI. */ - assign_parm_find_data_types (&all, parm, &data); + if (GET_CODE (parmreg) == CONCAT) + { + enum machine_mode submode = GET_MODE (XEXP (parmreg, 0)); - /* Early out for errors and void parameters. */ - if (data.passed_mode == VOIDmode) - { - SET_DECL_RTL (parm, const0_rtx); - DECL_INCOMING_RTL (parm) = DECL_RTL (parm); - continue; - } + regnor = REGNO (gen_realpart (submode, parmreg)); + regnoi = REGNO (gen_imagpart (submode, parmreg)); - if (current_function_stdarg && !TREE_CHAIN (parm)) - assign_parms_setup_varargs (&all, &data, false); + if (stack_parm != 0) + { + parm_reg_stack_loc[regnor] + = gen_realpart (submode, stack_parm); + parm_reg_stack_loc[regnoi] + = gen_imagpart (submode, stack_parm); + } + else + { + parm_reg_stack_loc[regnor] = 0; + parm_reg_stack_loc[regnoi] = 0; + } + } + else + parm_reg_stack_loc[REGNO (parmreg)] = stack_parm; + + /* Mark the register as eliminable if we did no conversion + and it was copied from memory at a fixed offset, + and the arg pointer was not copied to a pseudo-reg. + If the arg pointer is a pseudo reg or the offset formed + an invalid address, such memory-equivalences + as we make here would screw up life analysis for it. */ + if (nominal_mode == passed_mode + && ! did_conversion + && stack_parm != 0 + && GET_CODE (stack_parm) == MEM + && locate.offset.var == 0 + && reg_mentioned_p (virtual_incoming_args_rtx, + XEXP (stack_parm, 0))) + { + rtx linsn = get_last_insn (); + rtx sinsn, set; + + /* Mark complex types separately. */ + if (GET_CODE (parmreg) == CONCAT) + /* Scan backwards for the set of the real and + imaginary parts. */ + for (sinsn = linsn; sinsn != 0; + sinsn = prev_nonnote_insn (sinsn)) + { + set = single_set (sinsn); + if (set != 0 + && SET_DEST (set) == regno_reg_rtx [regnoi]) + REG_NOTES (sinsn) + = gen_rtx_EXPR_LIST (REG_EQUIV, + parm_reg_stack_loc[regnoi], + REG_NOTES (sinsn)); + else if (set != 0 + && SET_DEST (set) == regno_reg_rtx [regnor]) + REG_NOTES (sinsn) + = gen_rtx_EXPR_LIST (REG_EQUIV, + parm_reg_stack_loc[regnor], + REG_NOTES (sinsn)); + } + else if ((set = single_set (linsn)) != 0 + && SET_DEST (set) == parmreg) + REG_NOTES (linsn) + = gen_rtx_EXPR_LIST (REG_EQUIV, + stack_parm, REG_NOTES (linsn)); + } - /* Find out where the parameter arrives in this function. */ - assign_parm_find_entry_rtl (&all, &data); + /* For pointer data type, suggest pointer register. */ + if (POINTER_TYPE_P (TREE_TYPE (parm))) + mark_reg_pointer (parmreg, + TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm)))); - /* Find out where stack space for this parameter might be. */ - if (assign_parm_is_stack_parm (&all, &data)) - { - assign_parm_find_stack_rtl (parm, &data); - assign_parm_adjust_entry_rtl (&data); + /* If something wants our address, try to use ADDRESSOF. */ + if (TREE_ADDRESSABLE (parm)) + { + /* If we end up putting something into the stack, + fixup_var_refs_insns will need to make a pass over + all the instructions. It looks through the pending + sequences -- but it can't see the ones in the + CONVERSION_INSNS, if they're not on the sequence + stack. So, we go back to that sequence, just so that + the fixups will happen. */ + push_to_sequence (conversion_insns); + put_var_into_stack (parm, /*rescan=*/true); + conversion_insns = get_insns (); + end_sequence (); + } } + else + { + /* Value must be stored in the stack slot STACK_PARM + during function execution. */ - /* Record permanently how this parm was passed. */ - set_decl_incoming_rtl (parm, data.entry_parm); + if (promoted_mode != nominal_mode) + { + /* Conversion is required. */ + rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm)); - /* Update info on where next arg arrives in registers. */ - FUNCTION_ARG_ADVANCE (all.args_so_far, data.promoted_mode, - data.passed_type, data.named_arg); + emit_move_insn (tempreg, validize_mem (entry_parm)); - assign_parm_adjust_stack_rtl (&data); + push_to_sequence (conversion_insns); + entry_parm = convert_to_mode (nominal_mode, tempreg, + TREE_UNSIGNED (TREE_TYPE (parm))); + if (stack_parm) + /* ??? This may need a big-endian conversion on sparc64. */ + stack_parm = adjust_address (stack_parm, nominal_mode, 0); - if (assign_parm_setup_block_p (&data)) - assign_parm_setup_block (&all, parm, &data); - else if (data.passed_pointer || use_register_for_decl (parm)) - assign_parm_setup_reg (&all, parm, &data); - else - assign_parm_setup_stack (&all, parm, &data); + conversion_insns = get_insns (); + did_conversion = 1; + end_sequence (); + } + + if (entry_parm != stack_parm) + { + if (stack_parm == 0) + { + stack_parm + = assign_stack_local (GET_MODE (entry_parm), + GET_MODE_SIZE (GET_MODE (entry_parm)), + 0); + set_mem_attributes (stack_parm, parm, 1); + } + + if (promoted_mode != nominal_mode) + { + push_to_sequence (conversion_insns); + emit_move_insn (validize_mem (stack_parm), + validize_mem (entry_parm)); + conversion_insns = get_insns (); + end_sequence (); + } + else + emit_move_insn (validize_mem (stack_parm), + validize_mem (entry_parm)); + } + + SET_DECL_RTL (parm, stack_parm); + } } - if (targetm.calls.split_complex_arg && fnargs != all.orig_fnargs) - assign_parms_unsplit_complex (&all, fnargs); + if (targetm.calls.split_complex_arg && fnargs != orig_fnargs) + { + for (parm = orig_fnargs; parm; parm = TREE_CHAIN (parm)) + { + if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE + && targetm.calls.split_complex_arg (TREE_TYPE (parm))) + { + rtx tmp, real, imag; + enum machine_mode inner = GET_MODE_INNER (DECL_MODE (parm)); + + real = DECL_RTL (fnargs); + imag = DECL_RTL (TREE_CHAIN (fnargs)); + if (inner != GET_MODE (real)) + { + real = gen_lowpart_SUBREG (inner, real); + imag = gen_lowpart_SUBREG (inner, imag); + } + tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag); + SET_DECL_RTL (parm, tmp); + + real = DECL_INCOMING_RTL (fnargs); + imag = DECL_INCOMING_RTL (TREE_CHAIN (fnargs)); + if (inner != GET_MODE (real)) + { + real = gen_lowpart_SUBREG (inner, real); + imag = gen_lowpart_SUBREG (inner, imag); + } + tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag); + DECL_INCOMING_RTL (parm) = tmp; + fnargs = TREE_CHAIN (fnargs); + } + else + { + SET_DECL_RTL (parm, DECL_RTL (fnargs)); + DECL_INCOMING_RTL (parm) = DECL_INCOMING_RTL (fnargs); + } + fnargs = TREE_CHAIN (fnargs); + } + } /* Output all parameter conversion instructions (possibly including calls) now that all parameters have been copied out of hard registers. */ - emit_insn (all.conversion_insns); + emit_insn (conversion_insns); /* If we are receiving a struct value address as the first argument, set up the RTL for the function result. As this might require code to convert the transmitted address to Pmode, we do this here to ensure that possible preliminary conversions of the address have been emitted already. */ - if (all.function_result_decl) + if (function_result_decl) { - tree result = DECL_RESULT (current_function_decl); - rtx addr = DECL_RTL (all.function_result_decl); + tree result = DECL_RESULT (fndecl); + rtx addr = DECL_RTL (function_result_decl); rtx x; - if (DECL_BY_REFERENCE (result)) - x = addr; - else - { - addr = convert_memory_address (Pmode, addr); - x = gen_rtx_MEM (DECL_MODE (result), addr); - set_mem_attributes (x, result, 1); - } + addr = convert_memory_address (Pmode, addr); + x = gen_rtx_MEM (DECL_MODE (result), addr); + set_mem_attributes (x, result, 1); SET_DECL_RTL (result, x); } - /* We have aligned all the args, so add space for the pretend args. */ - current_function_pretend_args_size = all.pretend_args_size; - all.stack_args_size.constant += all.extra_pretend_bytes; - current_function_args_size = all.stack_args_size.constant; + last_parm_insn = get_last_insn (); + + current_function_args_size = stack_args_size.constant; /* Adjust function incoming argument size for alignment and minimum length. */ #ifdef REG_PARM_STACK_SPACE +#ifndef MAYBE_REG_PARM_STACK_SPACE current_function_args_size = MAX (current_function_args_size, REG_PARM_STACK_SPACE (fndecl)); #endif +#endif - current_function_args_size = CEIL_ROUND (current_function_args_size, - PARM_BOUNDARY / BITS_PER_UNIT); + current_function_args_size + = ((current_function_args_size + STACK_BYTES - 1) + / STACK_BYTES) * STACK_BYTES; #ifdef ARGS_GROW_DOWNWARD current_function_arg_offset_rtx - = (all.stack_args_size.var == 0 ? GEN_INT (-all.stack_args_size.constant) - : expand_expr (size_diffop (all.stack_args_size.var, - size_int (-all.stack_args_size.constant)), + = (stack_args_size.var == 0 ? GEN_INT (-stack_args_size.constant) + : expand_expr (size_diffop (stack_args_size.var, + size_int (-stack_args_size.constant)), NULL_RTX, VOIDmode, 0)); #else - current_function_arg_offset_rtx = ARGS_SIZE_RTX (all.stack_args_size); + current_function_arg_offset_rtx = ARGS_SIZE_RTX (stack_args_size); #endif /* See how many bytes, if any, of its args a function should try to pop @@ -3096,7 +5349,7 @@ assign_parms (tree fndecl) /* For stdarg.h function, save info about regs and stack space used by the named args. */ - current_function_args_info = all.args_so_far; + current_function_args_info = args_so_far; /* Set the rtx used for the function return value. Put this in its own variable so any optimizers that need this information don't have @@ -3121,8 +5374,13 @@ assign_parms (tree fndecl) { rtx real_decl_rtl; - real_decl_rtl = targetm.calls.function_value (TREE_TYPE (decl_result), - fndecl, true); +#ifdef FUNCTION_OUTGOING_VALUE + real_decl_rtl = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl_result), + fndecl); +#else + real_decl_rtl = FUNCTION_VALUE (TREE_TYPE (decl_result), + fndecl); +#endif REG_FUNCTION_VALUE_P (real_decl_rtl) = 1; /* The delay slot scheduler assumes that current_function_return_rtx holds the hard register containing the return value, not a @@ -3132,115 +5390,58 @@ assign_parms (tree fndecl) } } -/* A subroutine of gimplify_parameters, invoked via walk_tree. - For all seen types, gimplify their sizes. */ +/* If ARGS contains entries with complex types, split the entry into two + entries of the component type. Return a new list of substitutions are + needed, else the old list. */ static tree -gimplify_parm_type (tree *tp, int *walk_subtrees, void *data) +split_complex_args (tree args) { - tree t = *tp; + tree p; - *walk_subtrees = 0; - if (TYPE_P (t)) + /* Before allocating memory, check for the common case of no complex. */ + for (p = args; p; p = TREE_CHAIN (p)) { - if (POINTER_TYPE_P (t)) - *walk_subtrees = 1; - else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t)) - && !TYPE_SIZES_GIMPLIFIED (t)) - { - gimplify_type_sizes (t, (tree *) data); - *walk_subtrees = 1; - } + tree type = TREE_TYPE (p); + if (TREE_CODE (type) == COMPLEX_TYPE + && targetm.calls.split_complex_arg (type)) + goto found; } + return args; - return NULL; -} - -/* Gimplify the parameter list for current_function_decl. This involves - evaluating SAVE_EXPRs of variable sized parameters and generating code - to implement callee-copies reference parameters. Returns a list of - statements to add to the beginning of the function, or NULL if nothing - to do. */ - -tree -gimplify_parameters (void) -{ - struct assign_parm_data_all all; - tree fnargs, parm, stmts = NULL; - - assign_parms_initialize_all (&all); - fnargs = assign_parms_augmented_arg_list (&all); + found: + args = copy_list (args); - for (parm = fnargs; parm; parm = TREE_CHAIN (parm)) + for (p = args; p; p = TREE_CHAIN (p)) { - struct assign_parm_data_one data; - - /* Extract the type of PARM; adjust it according to ABI. */ - assign_parm_find_data_types (&all, parm, &data); - - /* Early out for errors and void parameters. */ - if (data.passed_mode == VOIDmode || DECL_SIZE (parm) == NULL) - continue; - - /* Update info on where next arg arrives in registers. */ - FUNCTION_ARG_ADVANCE (all.args_so_far, data.promoted_mode, - data.passed_type, data.named_arg); - - /* ??? Once upon a time variable_size stuffed parameter list - SAVE_EXPRs (amongst others) onto a pending sizes list. This - turned out to be less than manageable in the gimple world. - Now we have to hunt them down ourselves. */ - walk_tree_without_duplicates (&data.passed_type, - gimplify_parm_type, &stmts); - - if (!TREE_CONSTANT (DECL_SIZE (parm))) - { - gimplify_one_sizepos (&DECL_SIZE (parm), &stmts); - gimplify_one_sizepos (&DECL_SIZE_UNIT (parm), &stmts); - } - - if (data.passed_pointer) + tree type = TREE_TYPE (p); + if (TREE_CODE (type) == COMPLEX_TYPE + && targetm.calls.split_complex_arg (type)) { - tree type = TREE_TYPE (data.passed_type); - if (reference_callee_copied (&all.args_so_far, TYPE_MODE (type), - type, data.named_arg)) - { - tree local, t; + tree decl; + tree subtype = TREE_TYPE (type); - /* For constant sized objects, this is trivial; for - variable-sized objects, we have to play games. */ - if (TREE_CONSTANT (DECL_SIZE (parm))) - { - local = create_tmp_var (type, get_name (parm)); - DECL_IGNORED_P (local) = 0; - } - else - { - tree ptr_type, addr, args; - - ptr_type = build_pointer_type (type); - addr = create_tmp_var (ptr_type, get_name (parm)); - DECL_IGNORED_P (addr) = 0; - local = build_fold_indirect_ref (addr); - - args = tree_cons (NULL, DECL_SIZE_UNIT (parm), NULL); - t = built_in_decls[BUILT_IN_ALLOCA]; - t = build_function_call_expr (t, args); - t = fold_convert (ptr_type, t); - t = build2 (MODIFY_EXPR, void_type_node, addr, t); - gimplify_and_add (t, &stmts); - } + /* Rewrite the PARM_DECL's type with its component. */ + TREE_TYPE (p) = subtype; + DECL_ARG_TYPE (p) = TREE_TYPE (DECL_ARG_TYPE (p)); + DECL_MODE (p) = VOIDmode; + DECL_SIZE (p) = NULL; + DECL_SIZE_UNIT (p) = NULL; + layout_decl (p, 0); - t = build2 (MODIFY_EXPR, void_type_node, local, parm); - gimplify_and_add (t, &stmts); + /* Build a second synthetic decl. */ + decl = build_decl (PARM_DECL, NULL_TREE, subtype); + DECL_ARG_TYPE (decl) = DECL_ARG_TYPE (p); + layout_decl (decl, 0); - SET_DECL_VALUE_EXPR (parm, local); - DECL_HAS_VALUE_EXPR_P (parm) = 1; - } + /* Splice it in; skip the new decl. */ + TREE_CHAIN (decl) = TREE_CHAIN (p); + TREE_CHAIN (p) = decl; + p = decl; } } - return stmts; + return args; } /* Indicate whether REGNO is an incoming argument to the current function @@ -3256,12 +5457,12 @@ promoted_input_arg (unsigned int regno, enum machine_mode *pmode, int *punsigned for (arg = DECL_ARGUMENTS (current_function_decl); arg; arg = TREE_CHAIN (arg)) - if (REG_P (DECL_INCOMING_RTL (arg)) + if (GET_CODE (DECL_INCOMING_RTL (arg)) == REG && REGNO (DECL_INCOMING_RTL (arg)) == regno && TYPE_MODE (DECL_ARG_TYPE (arg)) == TYPE_MODE (TREE_TYPE (arg))) { enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg)); - int unsignedp = TYPE_UNSIGNED (TREE_TYPE (arg)); + int unsignedp = TREE_UNSIGNED (TREE_TYPE (arg)); mode = promote_mode (TREE_TYPE (arg), mode, &unsignedp, 1); if (mode == GET_MODE (DECL_INCOMING_RTL (arg)) @@ -3317,12 +5518,16 @@ locate_and_pad_parm (enum machine_mode passed_mode, tree type, int in_regs, { tree sizetree; enum direction where_pad; - unsigned int boundary; + int boundary; int reg_parm_stack_space = 0; int part_size_in_regs; #ifdef REG_PARM_STACK_SPACE +#ifdef MAYBE_REG_PARM_STACK_SPACE + reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE; +#else reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl); +#endif /* If we have found a stack parm before we reach the end of the area reserved for registers, skip that area. */ @@ -3343,21 +5548,17 @@ locate_and_pad_parm (enum machine_mode passed_mode, tree type, int in_regs, } #endif /* REG_PARM_STACK_SPACE */ - part_size_in_regs = (reg_parm_stack_space == 0 ? partial : 0); + part_size_in_regs = 0; + if (reg_parm_stack_space == 0) + part_size_in_regs = ((partial * UNITS_PER_WORD) + / (PARM_BOUNDARY / BITS_PER_UNIT) + * (PARM_BOUNDARY / BITS_PER_UNIT)); sizetree = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode)); where_pad = FUNCTION_ARG_PADDING (passed_mode, type); boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type); locate->where_pad = where_pad; - locate->boundary = boundary; - - /* Remember if the outgoing parameter requires extra alignment on the - calling function side. */ - if (boundary > PREFERRED_STACK_BOUNDARY) - boundary = PREFERRED_STACK_BOUNDARY; - if (cfun->stack_alignment_needed < boundary) - cfun->stack_alignment_needed = boundary; #ifdef ARGS_GROW_DOWNWARD locate->slot_offset.constant = -initial_offset_ptr->constant; @@ -3444,9 +5645,10 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary, HOST_WIDE_INT sp_offset = STACK_POINTER_OFFSET; #ifdef SPARC_STACK_BOUNDARY_HACK - /* ??? The SPARC port may claim a STACK_BOUNDARY higher than - the real alignment of %sp. However, when it does this, the - alignment of %sp+STACK_POINTER_OFFSET is STACK_BOUNDARY. */ + /* The sparc port has a bug. It sometimes claims a STACK_BOUNDARY + higher than the real alignment of %sp. However, when it does this, + the alignment of %sp+STACK_POINTER_OFFSET will be STACK_BOUNDARY. + This is a temporary hack while the sparc port is fixed. */ if (SPARC_STACK_BOUNDARY_HACK) sp_offset = 0; #endif @@ -3521,31 +5723,49 @@ pad_below (struct args_size *offset_ptr, enum machine_mode passed_mode, tree siz } /* Walk the tree of blocks describing the binding levels within a function - and warn about variables the might be killed by setjmp or vfork. + and warn about uninitialized variables. This is done after calling flow_analysis and before global_alloc clobbers the pseudo-regs to hard regs. */ void -setjmp_vars_warning (tree block) +uninitialized_vars_warning (tree block) { tree decl, sub; - for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl)) { - if (TREE_CODE (decl) == VAR_DECL + if (warn_uninitialized + && TREE_CODE (decl) == VAR_DECL + /* These warnings are unreliable for and aggregates + because assigning the fields one by one can fail to convince + flow.c that the entire aggregate was initialized. + Unions are troublesome because members may be shorter. */ + && ! AGGREGATE_TYPE_P (TREE_TYPE (decl)) + && DECL_RTL_SET_P (decl) + && GET_CODE (DECL_RTL (decl)) == REG + /* Global optimizations can make it difficult to determine if a + particular variable has been initialized. However, a VAR_DECL + with a nonzero DECL_INITIAL had an initializer, so do not + claim it is potentially uninitialized. + + When the DECL_INITIAL is NULL call the language hook to tell us + if we want to warn. */ + && (DECL_INITIAL (decl) == NULL_TREE || lang_hooks.decl_uninit (decl)) + && regno_uninitialized (REGNO (DECL_RTL (decl)))) + warning ("%J'%D' might be used uninitialized in this function", + decl, decl); + if (extra_warnings + && TREE_CODE (decl) == VAR_DECL && DECL_RTL_SET_P (decl) - && REG_P (DECL_RTL (decl)) + && GET_CODE (DECL_RTL (decl)) == REG && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl)))) - warning (0, "variable %q+D might be clobbered by %<longjmp%>" - " or %<vfork%>", - decl); + warning ("%Jvariable '%D' might be clobbered by `longjmp' or `vfork'", + decl, decl); } - for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub)) - setjmp_vars_warning (sub); + uninitialized_vars_warning (sub); } -/* Do the appropriate part of setjmp_vars_warning +/* Do the appropriate part of uninitialized_vars_warning but for arguments instead of local variables. */ void @@ -3555,13 +5775,379 @@ setjmp_args_warning (void) for (decl = DECL_ARGUMENTS (current_function_decl); decl; decl = TREE_CHAIN (decl)) if (DECL_RTL (decl) != 0 - && REG_P (DECL_RTL (decl)) + && GET_CODE (DECL_RTL (decl)) == REG && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl)))) - warning (0, "argument %q+D might be clobbered by %<longjmp%> or %<vfork%>", - decl); + warning ("%Jargument '%D' might be clobbered by `longjmp' or `vfork'", + decl, decl); +} + +/* If this function call setjmp, put all vars into the stack + unless they were declared `register'. */ + +void +setjmp_protect (tree block) +{ + tree decl, sub; + for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl)) + if ((TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL) + && DECL_RTL (decl) != 0 + && (GET_CODE (DECL_RTL (decl)) == REG + || (GET_CODE (DECL_RTL (decl)) == MEM + && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF)) + /* If this variable came from an inline function, it must be + that its life doesn't overlap the setjmp. If there was a + setjmp in the function, it would already be in memory. We + must exclude such variable because their DECL_RTL might be + set to strange things such as virtual_stack_vars_rtx. */ + && ! DECL_FROM_INLINE (decl) + && ( +#ifdef NON_SAVING_SETJMP + /* If longjmp doesn't restore the registers, + don't put anything in them. */ + NON_SAVING_SETJMP + || +#endif + ! DECL_REGISTER (decl))) + put_var_into_stack (decl, /*rescan=*/true); + for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub)) + setjmp_protect (sub); +} + +/* Like the previous function, but for args instead of local variables. */ + +void +setjmp_protect_args (void) +{ + tree decl; + for (decl = DECL_ARGUMENTS (current_function_decl); + decl; decl = TREE_CHAIN (decl)) + if ((TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL) + && DECL_RTL (decl) != 0 + && (GET_CODE (DECL_RTL (decl)) == REG + || (GET_CODE (DECL_RTL (decl)) == MEM + && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF)) + && ( + /* If longjmp doesn't restore the registers, + don't put anything in them. */ +#ifdef NON_SAVING_SETJMP + NON_SAVING_SETJMP + || +#endif + ! DECL_REGISTER (decl))) + put_var_into_stack (decl, /*rescan=*/true); } + +/* Return the context-pointer register corresponding to DECL, + or 0 if it does not need one. */ + +rtx +lookup_static_chain (tree decl) +{ + tree context = decl_function_context (decl); + tree link; + + if (context == 0 + || (TREE_CODE (decl) == FUNCTION_DECL && DECL_NO_STATIC_CHAIN (decl))) + return 0; + + /* We treat inline_function_decl as an alias for the current function + because that is the inline function whose vars, types, etc. + are being merged into the current function. + See expand_inline_function. */ + if (context == current_function_decl || context == inline_function_decl) + return virtual_stack_vars_rtx; + for (link = context_display; link; link = TREE_CHAIN (link)) + if (TREE_PURPOSE (link) == context) + return RTL_EXPR_RTL (TREE_VALUE (link)); + + abort (); +} +/* Convert a stack slot address ADDR for variable VAR + (from a containing function) + into an address valid in this function (using a static chain). */ + +rtx +fix_lexical_addr (rtx addr, tree var) +{ + rtx basereg; + HOST_WIDE_INT displacement; + tree context = decl_function_context (var); + struct function *fp; + rtx base = 0; + + /* If this is the present function, we need not do anything. */ + if (context == current_function_decl || context == inline_function_decl) + return addr; + + fp = find_function_data (context); + + if (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == MEM) + addr = XEXP (XEXP (addr, 0), 0); + + /* Decode given address as base reg plus displacement. */ + if (GET_CODE (addr) == REG) + basereg = addr, displacement = 0; + else if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT) + basereg = XEXP (addr, 0), displacement = INTVAL (XEXP (addr, 1)); + else + abort (); + + /* We accept vars reached via the containing function's + incoming arg pointer and via its stack variables pointer. */ + if (basereg == fp->internal_arg_pointer) + { + /* If reached via arg pointer, get the arg pointer value + out of that function's stack frame. + + There are two cases: If a separate ap is needed, allocate a + slot in the outer function for it and dereference it that way. + This is correct even if the real ap is actually a pseudo. + Otherwise, just adjust the offset from the frame pointer to + compensate. */ + +#ifdef NEED_SEPARATE_AP + rtx addr; + + addr = get_arg_pointer_save_area (fp); + addr = fix_lexical_addr (XEXP (addr, 0), var); + addr = memory_address (Pmode, addr); + + base = gen_rtx_MEM (Pmode, addr); + set_mem_alias_set (base, get_frame_alias_set ()); + base = copy_to_reg (base); +#else + displacement += (FIRST_PARM_OFFSET (context) - STARTING_FRAME_OFFSET); + base = lookup_static_chain (var); +#endif + } + + else if (basereg == virtual_stack_vars_rtx) + { + /* This is the same code as lookup_static_chain, duplicated here to + avoid an extra call to decl_function_context. */ + tree link; + + for (link = context_display; link; link = TREE_CHAIN (link)) + if (TREE_PURPOSE (link) == context) + { + base = RTL_EXPR_RTL (TREE_VALUE (link)); + break; + } + } + + if (base == 0) + abort (); + + /* Use same offset, relative to appropriate static chain or argument + pointer. */ + return plus_constant (base, displacement); +} + +/* Return the address of the trampoline for entering nested fn FUNCTION. + If necessary, allocate a trampoline (in the stack frame) + and emit rtl to initialize its contents (at entry to this function). */ + +rtx +trampoline_address (tree function) +{ + tree link; + tree rtlexp; + rtx tramp; + struct function *fp; + tree fn_context; + + /* Find an existing trampoline and return it. */ + for (link = trampoline_list; link; link = TREE_CHAIN (link)) + if (TREE_PURPOSE (link) == function) + return + adjust_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0)); + + for (fp = outer_function_chain; fp; fp = fp->outer) + for (link = fp->x_trampoline_list; link; link = TREE_CHAIN (link)) + if (TREE_PURPOSE (link) == function) + { + tramp = fix_lexical_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0), + function); + return adjust_trampoline_addr (tramp); + } + + /* None exists; we must make one. */ + + /* Find the `struct function' for the function containing FUNCTION. */ + fp = 0; + fn_context = decl_function_context (function); + if (fn_context != current_function_decl + && fn_context != inline_function_decl) + fp = find_function_data (fn_context); + + /* Allocate run-time space for this trampoline. */ + /* If rounding needed, allocate extra space + to ensure we have TRAMPOLINE_SIZE bytes left after rounding up. */ +#define TRAMPOLINE_REAL_SIZE \ + (TRAMPOLINE_SIZE + (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT) - 1) + tramp = assign_stack_local_1 (BLKmode, TRAMPOLINE_REAL_SIZE, 0, + fp ? fp : cfun); + /* Record the trampoline for reuse and note it for later initialization + by expand_function_end. */ + if (fp != 0) + { + rtlexp = make_node (RTL_EXPR); + RTL_EXPR_RTL (rtlexp) = tramp; + fp->x_trampoline_list = tree_cons (function, rtlexp, + fp->x_trampoline_list); + } + else + { + /* Make the RTL_EXPR node temporary, not momentary, so that the + trampoline_list doesn't become garbage. */ + rtlexp = make_node (RTL_EXPR); + + RTL_EXPR_RTL (rtlexp) = tramp; + trampoline_list = tree_cons (function, rtlexp, trampoline_list); + } + + tramp = fix_lexical_addr (XEXP (tramp, 0), function); + return adjust_trampoline_addr (tramp); +} + +/* Given a trampoline address, + round it to multiple of TRAMPOLINE_ALIGNMENT. */ + +static rtx +round_trampoline_addr (rtx tramp) +{ + /* Round address up to desired boundary. */ + rtx temp = gen_reg_rtx (Pmode); + rtx addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1); + rtx mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT); + + temp = expand_simple_binop (Pmode, PLUS, tramp, addend, + temp, 0, OPTAB_LIB_WIDEN); + tramp = expand_simple_binop (Pmode, AND, temp, mask, + temp, 0, OPTAB_LIB_WIDEN); + + return tramp; +} + +/* Given a trampoline address, round it then apply any + platform-specific adjustments so that the result can be used for a + function call . */ + +static rtx +adjust_trampoline_addr (rtx tramp) +{ + tramp = round_trampoline_addr (tramp); +#ifdef TRAMPOLINE_ADJUST_ADDRESS + TRAMPOLINE_ADJUST_ADDRESS (tramp); +#endif + return tramp; +} + +/* Put all this function's BLOCK nodes including those that are chained + onto the first block into a vector, and return it. + Also store in each NOTE for the beginning or end of a block + the index of that block in the vector. + The arguments are BLOCK, the chain of top-level blocks of the function, + and INSNS, the insn chain of the function. */ + +void +identify_blocks (void) +{ + int n_blocks; + tree *block_vector, *last_block_vector; + tree *block_stack; + tree block = DECL_INITIAL (current_function_decl); + + if (block == 0) + return; + + /* Fill the BLOCK_VECTOR with all of the BLOCKs in this function, in + depth-first order. */ + block_vector = get_block_vector (block, &n_blocks); + block_stack = xmalloc (n_blocks * sizeof (tree)); + + last_block_vector = identify_blocks_1 (get_insns (), + block_vector + 1, + block_vector + n_blocks, + block_stack); + + /* If we didn't use all of the subblocks, we've misplaced block notes. */ + /* ??? This appears to happen all the time. Latent bugs elsewhere? */ + if (0 && last_block_vector != block_vector + n_blocks) + abort (); + + free (block_vector); + free (block_stack); +} + +/* Subroutine of identify_blocks. Do the block substitution on the + insn chain beginning with INSNS. Recurse for CALL_PLACEHOLDER chains. + + BLOCK_STACK is pushed and popped for each BLOCK_BEGIN/BLOCK_END pair. + BLOCK_VECTOR is incremented for each block seen. */ + +static tree * +identify_blocks_1 (rtx insns, tree *block_vector, tree *end_block_vector, + tree *orig_block_stack) +{ + rtx insn; + tree *block_stack = orig_block_stack; + + for (insn = insns; insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == NOTE) + { + if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG) + { + tree b; + + /* If there are more block notes than BLOCKs, something + is badly wrong. */ + if (block_vector == end_block_vector) + abort (); + + b = *block_vector++; + NOTE_BLOCK (insn) = b; + *block_stack++ = b; + } + else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END) + { + /* If there are more NOTE_INSN_BLOCK_ENDs than + NOTE_INSN_BLOCK_BEGs, something is badly wrong. */ + if (block_stack == orig_block_stack) + abort (); + + NOTE_BLOCK (insn) = *--block_stack; + } + } + else if (GET_CODE (insn) == CALL_INSN + && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) + { + rtx cp = PATTERN (insn); + + block_vector = identify_blocks_1 (XEXP (cp, 0), block_vector, + end_block_vector, block_stack); + if (XEXP (cp, 1)) + block_vector = identify_blocks_1 (XEXP (cp, 1), block_vector, + end_block_vector, block_stack); + if (XEXP (cp, 2)) + block_vector = identify_blocks_1 (XEXP (cp, 2), block_vector, + end_block_vector, block_stack); + } + } + + /* If there are more NOTE_INSN_BLOCK_BEGINs than NOTE_INSN_BLOCK_ENDs, + something is badly wrong. */ + if (block_stack != orig_block_stack) + abort (); + + return block_vector; +} + /* Identify BLOCKs referenced by more than one NOTE_INSN_BLOCK_{BEG,END}, and create duplicate blocks. */ /* ??? Need an option to either create block fragments or to create @@ -3572,15 +6158,15 @@ void reorder_blocks (void) { tree block = DECL_INITIAL (current_function_decl); - VEC(tree,heap) *block_stack; + varray_type block_stack; if (block == NULL_TREE) return; - block_stack = VEC_alloc (tree, heap, 10); + VARRAY_TREE_INIT (block_stack, 10, "block_stack"); /* Reset the TREE_ASM_WRITTEN bit for all blocks. */ - clear_block_marks (block); + reorder_blocks_0 (block); /* Prune the old trees away, so that they don't get in the way. */ BLOCK_SUBBLOCKS (block) = NULL_TREE; @@ -3590,46 +6176,46 @@ reorder_blocks (void) reorder_blocks_1 (get_insns (), block, &block_stack); BLOCK_SUBBLOCKS (block) = blocks_nreverse (BLOCK_SUBBLOCKS (block)); - VEC_free (tree, heap, block_stack); + /* Remove deleted blocks from the block fragment chains. */ + reorder_fix_fragments (block); } /* Helper function for reorder_blocks. Reset TREE_ASM_WRITTEN. */ -void -clear_block_marks (tree block) +static void +reorder_blocks_0 (tree block) { while (block) { TREE_ASM_WRITTEN (block) = 0; - clear_block_marks (BLOCK_SUBBLOCKS (block)); + reorder_blocks_0 (BLOCK_SUBBLOCKS (block)); block = BLOCK_CHAIN (block); } } static void -reorder_blocks_1 (rtx insns, tree current_block, VEC(tree,heap) **p_block_stack) +reorder_blocks_1 (rtx insns, tree current_block, varray_type *p_block_stack) { rtx insn; for (insn = insns; insn; insn = NEXT_INSN (insn)) { - if (NOTE_P (insn)) + if (GET_CODE (insn) == NOTE) { if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG) { tree block = NOTE_BLOCK (insn); - tree origin; - - origin = (BLOCK_FRAGMENT_ORIGIN (block) - ? BLOCK_FRAGMENT_ORIGIN (block) - : block); /* If we have seen this block before, that means it now spans multiple address regions. Create a new fragment. */ if (TREE_ASM_WRITTEN (block)) { tree new_block = copy_node (block); + tree origin; + origin = (BLOCK_FRAGMENT_ORIGIN (block) + ? BLOCK_FRAGMENT_ORIGIN (block) + : block); BLOCK_FRAGMENT_ORIGIN (new_block) = origin; BLOCK_FRAGMENT_CHAIN (new_block) = BLOCK_FRAGMENT_CHAIN (origin); @@ -3646,31 +6232,94 @@ reorder_blocks_1 (rtx insns, tree current_block, VEC(tree,heap) **p_block_stack) will cause infinite recursion. */ if (block != current_block) { - if (block != origin) - gcc_assert (BLOCK_SUPERCONTEXT (origin) == current_block); - BLOCK_SUPERCONTEXT (block) = current_block; BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block); BLOCK_SUBBLOCKS (current_block) = block; - current_block = origin; + current_block = block; } - VEC_safe_push (tree, heap, *p_block_stack, block); + VARRAY_PUSH_TREE (*p_block_stack, block); } else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END) { - NOTE_BLOCK (insn) = VEC_pop (tree, *p_block_stack); + NOTE_BLOCK (insn) = VARRAY_TOP_TREE (*p_block_stack); + VARRAY_POP (*p_block_stack); BLOCK_SUBBLOCKS (current_block) = blocks_nreverse (BLOCK_SUBBLOCKS (current_block)); current_block = BLOCK_SUPERCONTEXT (current_block); } } + else if (GET_CODE (insn) == CALL_INSN + && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) + { + rtx cp = PATTERN (insn); + reorder_blocks_1 (XEXP (cp, 0), current_block, p_block_stack); + if (XEXP (cp, 1)) + reorder_blocks_1 (XEXP (cp, 1), current_block, p_block_stack); + if (XEXP (cp, 2)) + reorder_blocks_1 (XEXP (cp, 2), current_block, p_block_stack); + } + } +} + +/* Rationalize BLOCK_FRAGMENT_ORIGIN. If an origin block no longer + appears in the block tree, select one of the fragments to become + the new origin block. */ + +static void +reorder_fix_fragments (tree block) +{ + while (block) + { + tree dup_origin = BLOCK_FRAGMENT_ORIGIN (block); + tree new_origin = NULL_TREE; + + if (dup_origin) + { + if (! TREE_ASM_WRITTEN (dup_origin)) + { + new_origin = BLOCK_FRAGMENT_CHAIN (dup_origin); + + /* Find the first of the remaining fragments. There must + be at least one -- the current block. */ + while (! TREE_ASM_WRITTEN (new_origin)) + new_origin = BLOCK_FRAGMENT_CHAIN (new_origin); + BLOCK_FRAGMENT_ORIGIN (new_origin) = NULL_TREE; + } + } + else if (! dup_origin) + new_origin = block; + + /* Re-root the rest of the fragments to the new origin. In the + case that DUP_ORIGIN was null, that means BLOCK was the origin + of a chain of fragments and we want to remove those fragments + that didn't make it to the output. */ + if (new_origin) + { + tree *pp = &BLOCK_FRAGMENT_CHAIN (new_origin); + tree chain = *pp; + + while (chain) + { + if (TREE_ASM_WRITTEN (chain)) + { + BLOCK_FRAGMENT_ORIGIN (chain) = new_origin; + *pp = chain; + pp = &BLOCK_FRAGMENT_CHAIN (chain); + } + chain = BLOCK_FRAGMENT_CHAIN (chain); + } + *pp = NULL_TREE; + } + + reorder_fix_fragments (BLOCK_SUBBLOCKS (block)); + block = BLOCK_CHAIN (block); } } /* Reverse the order of elements in the chain T of blocks, and return the new head of the chain (old last element). */ -tree +static tree blocks_nreverse (tree t) { tree prev = 0, decl, next; @@ -3723,7 +6372,7 @@ get_block_vector (tree block, int *n_blocks_p) tree *block_vector; *n_blocks_p = all_blocks (block, NULL); - block_vector = XNEWVEC (tree, *n_blocks_p); + block_vector = xmalloc (*n_blocks_p * sizeof (tree)); all_blocks (block, block_vector); return block_vector; @@ -3788,10 +6437,11 @@ void allocate_struct_function (tree fndecl) { tree result; - tree fntype = fndecl ? TREE_TYPE (fndecl) : NULL_TREE; cfun = ggc_alloc_cleared (sizeof (struct function)); + max_parm_reg = LAST_VIRTUAL_REGISTER + 1; + cfun->stack_alignment_needed = STACK_BOUNDARY; cfun->preferred_stack_boundary = STACK_BOUNDARY; @@ -3799,16 +6449,17 @@ allocate_struct_function (tree fndecl) cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL; + init_stmt_for_function (); init_eh_for_function (); - lang_hooks.function.init (cfun); + (*lang_hooks.function.init) (cfun); if (init_machine_status) cfun->machine = (*init_machine_status) (); if (fndecl == NULL) return; - DECL_STRUCT_FUNCTION (fndecl) = cfun; + DECL_SAVED_INSNS (fndecl) = cfun; cfun->decl = fndecl; result = DECL_RESULT (fndecl); @@ -3822,15 +6473,9 @@ allocate_struct_function (tree fndecl) current_function_returns_pointer = POINTER_TYPE_P (TREE_TYPE (result)); - current_function_stdarg - = (fntype - && TYPE_ARG_TYPES (fntype) != 0 - && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) - != void_type_node)); - - /* Assume all registers in stdarg functions need to be saved. */ - cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE; - cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE; + current_function_needs_context + = (decl_function_context (current_function_decl) != 0 + && ! DECL_NO_STATIC_CHAIN (current_function_decl)); } /* Reset cfun, and other non-struct-function variables to defaults as @@ -3839,8 +6484,8 @@ allocate_struct_function (tree fndecl) static void prepare_function_start (tree fndecl) { - if (fndecl && DECL_STRUCT_FUNCTION (fndecl)) - cfun = DECL_STRUCT_FUNCTION (fndecl); + if (fndecl && DECL_SAVED_INSNS (fndecl)) + cfun = DECL_SAVED_INSNS (fndecl); else allocate_struct_function (fndecl); init_emit (); @@ -3855,6 +6500,10 @@ prepare_function_start (tree fndecl) /* We haven't done register allocation yet. */ reg_renumber = 0; + /* Indicate that we need to distinguish between the return value of the + present function and the return value of a function being called. */ + rtx_equal_function_value_matters = 1; + /* Indicate that we have not instantiated virtual registers yet. */ virtuals_instantiated = 0; @@ -3883,11 +6532,14 @@ init_function_start (tree subr) { prepare_function_start (subr); + /* Within function body, compute a type's size as soon it is laid out. */ + immediate_size_expand++; + /* Prevent ever trying to delete the first instruction of a function. Also tell final how to output a linenum before the function prologue. Note linenums could be missing, e.g. when compiling a Java .class file. */ - if (! DECL_IS_BUILTIN (subr)) + if (DECL_SOURCE_LINE (subr)) emit_line_note (DECL_SOURCE_LOCATION (subr)); /* Make sure first insn is a note even if we don't want linenums. @@ -3897,144 +6549,96 @@ init_function_start (tree subr) /* Warn if this value is an aggregate type, regardless of which calling convention we are using for it. */ - if (AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr)))) - warning (OPT_Waggregate_return, "function returns an aggregate"); + if (warn_aggregate_return + && AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr)))) + warning ("function returns an aggregate"); } /* Make sure all values used by the optimization passes have sane defaults. */ -unsigned int +void init_function_for_compilation (void) { reg_renumber = 0; - /* No prologue/epilogue insns yet. Make sure that these vectors are - empty. */ - gcc_assert (VEC_length (int, prologue) == 0); - gcc_assert (VEC_length (int, epilogue) == 0); - gcc_assert (VEC_length (int, sibcall_epilogue) == 0); - return 0; + /* No prologue/epilogue insns yet. */ + VARRAY_GROW (prologue, 0); + VARRAY_GROW (epilogue, 0); + VARRAY_GROW (sibcall_epilogue, 0); } -struct tree_opt_pass pass_init_function = -{ - NULL, /* name */ - NULL, /* gate */ - init_function_for_compilation, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - 0, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ - 0 /* letter */ -}; +/* Expand a call to __main at the beginning of a possible main function. */ +#if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main) +#undef HAS_INIT_SECTION +#define HAS_INIT_SECTION +#endif void expand_main_function (void) { -#if (defined(INVOKE__main) \ - || (!defined(HAS_INIT_SECTION) \ - && !defined(INIT_SECTION_ASM_OP) \ - && !defined(INIT_ARRAY_SECTION_ASM_OP))) - emit_library_call (init_one_libfunc (NAME__MAIN), LCT_NORMAL, VOIDmode, 0); -#endif -} - -/* Expand code to initialize the stack_protect_guard. This is invoked at - the beginning of a function to be protected. */ +#ifdef FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN + if (FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN) + { + int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; + rtx tmp, seq; -#ifndef HAVE_stack_protect_set -# define HAVE_stack_protect_set 0 -# define gen_stack_protect_set(x,y) (gcc_unreachable (), NULL_RTX) + start_sequence (); + /* Forcibly align the stack. */ +#ifdef STACK_GROWS_DOWNWARD + tmp = expand_simple_binop (Pmode, AND, stack_pointer_rtx, GEN_INT(-align), + stack_pointer_rtx, 1, OPTAB_WIDEN); +#else + tmp = expand_simple_binop (Pmode, PLUS, stack_pointer_rtx, + GEN_INT (align - 1), NULL_RTX, 1, OPTAB_WIDEN); + tmp = expand_simple_binop (Pmode, AND, tmp, GEN_INT (-align), + stack_pointer_rtx, 1, OPTAB_WIDEN); #endif + if (tmp != stack_pointer_rtx) + emit_move_insn (stack_pointer_rtx, tmp); -void -stack_protect_prologue (void) -{ - tree guard_decl = targetm.stack_protect_guard (); - rtx x, y; - - /* Avoid expand_expr here, because we don't want guard_decl pulled - into registers unless absolutely necessary. And we know that - cfun->stack_protect_guard is a local stack slot, so this skips - all the fluff. */ - x = validize_mem (DECL_RTL (cfun->stack_protect_guard)); - y = validize_mem (DECL_RTL (guard_decl)); - - /* Allow the target to copy from Y to X without leaking Y into a - register. */ - if (HAVE_stack_protect_set) - { - rtx insn = gen_stack_protect_set (x, y); - if (insn) - { - emit_insn (insn); - return; - } - } - - /* Otherwise do a straight move. */ - emit_move_insn (x, y); -} + /* Enlist allocate_dynamic_stack_space to pick up the pieces. */ + tmp = force_reg (Pmode, const0_rtx); + allocate_dynamic_stack_space (tmp, NULL_RTX, BIGGEST_ALIGNMENT); + seq = get_insns (); + end_sequence (); -/* Expand code to verify the stack_protect_guard. This is invoked at - the end of a function to be protected. */ + for (tmp = get_last_insn (); tmp; tmp = PREV_INSN (tmp)) + if (NOTE_P (tmp) && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_FUNCTION_BEG) + break; + if (tmp) + emit_insn_before (seq, tmp); + else + emit_insn (seq); + } +#endif -#ifndef HAVE_stack_protect_test -# define HAVE_stack_protect_test 0 -# define gen_stack_protect_test(x, y, z) (gcc_unreachable (), NULL_RTX) +#ifndef HAS_INIT_SECTION + emit_library_call (init_one_libfunc (NAME__MAIN), LCT_NORMAL, VOIDmode, 0); #endif +} + +/* The PENDING_SIZES represent the sizes of variable-sized types. + Create RTL for the various sizes now (using temporary variables), + so that we can refer to the sizes from the RTL we are generating + for the current function. The PENDING_SIZES are a TREE_LIST. The + TREE_VALUE of each node is a SAVE_EXPR. */ void -stack_protect_epilogue (void) +expand_pending_sizes (tree pending_sizes) { - tree guard_decl = targetm.stack_protect_guard (); - rtx label = gen_label_rtx (); - rtx x, y, tmp; - - /* Avoid expand_expr here, because we don't want guard_decl pulled - into registers unless absolutely necessary. And we know that - cfun->stack_protect_guard is a local stack slot, so this skips - all the fluff. */ - x = validize_mem (DECL_RTL (cfun->stack_protect_guard)); - y = validize_mem (DECL_RTL (guard_decl)); - - /* Allow the target to compare Y with X without leaking either into - a register. */ - switch (HAVE_stack_protect_test != 0) - { - case 1: - tmp = gen_stack_protect_test (x, y, label); - if (tmp) - { - emit_insn (tmp); - break; - } - /* FALLTHRU */ + tree tem; - default: - emit_cmp_and_jump_insns (x, y, EQ, NULL_RTX, ptr_mode, 1, label); - break; + /* Evaluate now the sizes of any types declared among the arguments. */ + for (tem = pending_sizes; tem; tem = TREE_CHAIN (tem)) + { + expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0); + /* Flush the queue in case this parameter declaration has + side-effects. */ + emit_queue (); } - - /* The noreturn predictor has been moved to the tree level. The rtl-level - predictors estimate this branch about 20%, which isn't enough to get - things moved out of line. Since this is the only extant case of adding - a noreturn function at the rtl level, it doesn't seem worth doing ought - except adding the prediction by hand. */ - tmp = get_last_insn (); - if (JUMP_P (tmp)) - predict_insn_def (tmp, PRED_NORETURN, TAKEN); - - expand_expr_stmt (targetm.stack_protect_fail ()); - emit_label (label); } - + /* Start the RTL for a new function, and set variables used for emitting RTL. SUBR is the FUNCTION_DECL node. @@ -4042,12 +6646,19 @@ stack_protect_epilogue (void) the function's parameters, which must be run at any return statement. */ void -expand_function_start (tree subr) +expand_function_start (tree subr, int parms_have_cleanups) { + tree tem; + rtx last_ptr = NULL_RTX; + /* Make sure volatile mem refs aren't considered valid operands of arithmetic insns. */ init_recog_no_volatile (); + current_function_instrument_entry_exit + = (flag_instrument_function_entry_exit + && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr)); + current_function_profile = (profile_flag && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr)); @@ -4055,6 +6666,27 @@ expand_function_start (tree subr) current_function_limit_stack = (stack_limit_rtx != NULL_RTX && ! DECL_NO_LIMIT_STACK (subr)); + /* If function gets a static chain arg, store it in the stack frame. + Do this first, so it gets the first stack slot offset. */ + if (current_function_needs_context) + { + last_ptr = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0); + + /* Delay copying static chain if it is not a register to avoid + conflicts with regs used for parameters. */ + if (! SMALL_REGISTER_CLASSES + || GET_CODE (static_chain_incoming_rtx) == REG) + emit_move_insn (last_ptr, static_chain_incoming_rtx); + } + + /* If the parameters of this function need cleaning up, get a label + for the beginning of the code which executes those cleanups. This must + be done before doing anything with return_label. */ + if (parms_have_cleanups) + cleanup_label = gen_label_rtx (); + else + cleanup_label = 0; + /* Make the label for return statements to jump to. Do not special case machines with special return instructions -- they will be handled later during jump, ifcvt, or epilogue creation. */ @@ -4079,7 +6711,7 @@ expand_function_start (tree subr) else #endif { - rtx sv = targetm.calls.struct_value_rtx (TREE_TYPE (subr), 2); + rtx sv = targetm.calls.struct_value_rtx (TREE_TYPE (subr), 1); /* Expect to be passed the address of a place to store the value. If it is passed as an argument, assign_parms will take care of it. */ @@ -4091,12 +6723,8 @@ expand_function_start (tree subr) } if (value_address) { - rtx x = value_address; - if (!DECL_BY_REFERENCE (DECL_RESULT (subr))) - { - x = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), x); - set_mem_attributes (x, DECL_RESULT (subr), 1); - } + rtx x = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address); + set_mem_attributes (x, DECL_RESULT (subr), 1); SET_DECL_RTL (DECL_RESULT (subr), x); } } @@ -4107,32 +6735,22 @@ expand_function_start (tree subr) { /* Compute the return values into a pseudo reg, which we will copy into the true return register after the cleanups are done. */ - tree return_type = TREE_TYPE (DECL_RESULT (subr)); - if (TYPE_MODE (return_type) != BLKmode - && targetm.calls.return_in_msb (return_type)) - /* expand_function_end will insert the appropriate padding in - this case. Use the return value's natural (unpadded) mode - within the function proper. */ - SET_DECL_RTL (DECL_RESULT (subr), - gen_reg_rtx (TYPE_MODE (return_type))); + + /* In order to figure out what mode to use for the pseudo, we + figure out what the mode of the eventual return register will + actually be, and use that. */ + rtx hard_reg + = hard_function_value (TREE_TYPE (DECL_RESULT (subr)), + subr, 1); + + /* Structures that are returned in registers are not aggregate_value_p, + so we may see a PARALLEL or a REG. */ + if (REG_P (hard_reg)) + SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg))); + else if (GET_CODE (hard_reg) == PARALLEL) + SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg)); else - { - /* In order to figure out what mode to use for the pseudo, we - figure out what the mode of the eventual return register will - actually be, and use that. */ - rtx hard_reg = hard_function_value (return_type, subr, 0, 1); - - /* Structures that are returned in registers are not - aggregate_value_p, so we may see a PARALLEL or a REG. */ - if (REG_P (hard_reg)) - SET_DECL_RTL (DECL_RESULT (subr), - gen_reg_rtx (GET_MODE (hard_reg))); - else - { - gcc_assert (GET_CODE (hard_reg) == PARALLEL); - SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg)); - } - } + abort (); /* Set DECL_REGISTER flag so that expand_function_end will copy the result to the real return register(s). */ @@ -4141,41 +6759,15 @@ expand_function_start (tree subr) /* Initialize rtx for parameters and local variables. In some cases this requires emitting insns. */ - assign_parms (subr); - - /* If function gets a static chain arg, store it. */ - if (cfun->static_chain_decl) - { - tree parm = cfun->static_chain_decl; - rtx local = gen_reg_rtx (Pmode); - - set_decl_incoming_rtl (parm, static_chain_incoming_rtx); - SET_DECL_RTL (parm, local); - mark_reg_pointer (local, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm)))); - - emit_move_insn (local, static_chain_incoming_rtx); - } - - /* If the function receives a non-local goto, then store the - bits we need to restore the frame pointer. */ - if (cfun->nonlocal_goto_save_area) - { - tree t_save; - rtx r_save; - /* ??? We need to do this save early. Unfortunately here is - before the frame variable gets declared. Help out... */ - expand_var (TREE_OPERAND (cfun->nonlocal_goto_save_area, 0)); + assign_parms (subr); - t_save = build4 (ARRAY_REF, ptr_type_node, - cfun->nonlocal_goto_save_area, - integer_zero_node, NULL_TREE, NULL_TREE); - r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE); - r_save = convert_memory_address (Pmode, r_save); + /* Copy the static chain now if it wasn't a register. The delay is to + avoid conflicts with the parameter passing registers. */ - emit_move_insn (r_save, virtual_stack_vars_rtx); - update_nonlocal_goto_save_area (); - } + if (SMALL_REGISTER_CLASSES && current_function_needs_context) + if (GET_CODE (static_chain_incoming_rtx) != REG) + emit_move_insn (last_ptr, static_chain_incoming_rtx); /* The following was moved from init_function_start. The move is supposed to make sdb output more accurate. */ @@ -4183,10 +6775,71 @@ expand_function_start (tree subr) as opposed to parm setup. */ emit_note (NOTE_INSN_FUNCTION_BEG); - gcc_assert (NOTE_P (get_last_insn ())); - + if (GET_CODE (get_last_insn ()) != NOTE) + emit_note (NOTE_INSN_DELETED); parm_birth_insn = get_last_insn (); + context_display = 0; + if (current_function_needs_context) + { + /* Fetch static chain values for containing functions. */ + tem = decl_function_context (current_function_decl); + /* Copy the static chain pointer into a pseudo. If we have + small register classes, copy the value from memory if + static_chain_incoming_rtx is a REG. */ + if (tem) + { + /* If the static chain originally came in a register, put it back + there, then move it out in the next insn. The reason for + this peculiar code is to satisfy function integration. */ + if (SMALL_REGISTER_CLASSES + && GET_CODE (static_chain_incoming_rtx) == REG) + emit_move_insn (static_chain_incoming_rtx, last_ptr); + last_ptr = copy_to_reg (static_chain_incoming_rtx); + } + + while (tem) + { + tree rtlexp = make_node (RTL_EXPR); + + RTL_EXPR_RTL (rtlexp) = last_ptr; + context_display = tree_cons (tem, rtlexp, context_display); + tem = decl_function_context (tem); + if (tem == 0) + break; + /* Chain through stack frames, assuming pointer to next lexical frame + is found at the place we always store it. */ +#ifdef FRAME_GROWS_DOWNWARD + last_ptr = plus_constant (last_ptr, + -(HOST_WIDE_INT) GET_MODE_SIZE (Pmode)); +#endif + last_ptr = gen_rtx_MEM (Pmode, memory_address (Pmode, last_ptr)); + set_mem_alias_set (last_ptr, get_frame_alias_set ()); + last_ptr = copy_to_reg (last_ptr); + + /* If we are not optimizing, ensure that we know that this + piece of context is live over the entire function. */ + if (! optimize) + save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, last_ptr, + save_expr_regs); + } + } + + if (current_function_instrument_entry_exit) + { + rtx fun = DECL_RTL (current_function_decl); + if (GET_CODE (fun) == MEM) + fun = XEXP (fun, 0); + else + abort (); + emit_library_call (profile_function_entry_libfunc, LCT_NORMAL, VOIDmode, + 2, fun, Pmode, + expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, + 0, + hard_frame_pointer_rtx), + Pmode); + } + if (current_function_profile) { #ifdef PROFILE_HOOK @@ -4194,10 +6847,13 @@ expand_function_start (tree subr) #endif } - /* After the display initializations is where the stack checking - probe should go. */ - if(flag_stack_check) - stack_check_probe_note = emit_note (NOTE_INSN_DELETED); + /* After the display initializations is where the tail-recursion label + should go, if we end up needing one. Ensure we have a NOTE here + since some things (like trampolines) get placed before this. */ + tail_recursion_reentry = emit_note (NOTE_INSN_DELETED); + + /* Evaluate now the sizes of any types declared among the arguments. */ + expand_pending_sizes (nreverse (get_pending_sizes ())); /* Make sure there is a line number after the function entry setup code. */ force_next_line_note (); @@ -4230,7 +6886,7 @@ diddle_return_value (void (*doit) (rtx, void *), void *arg) if (! outgoing) return; - if (REG_P (outgoing)) + if (GET_CODE (outgoing) == REG) (*doit) (outgoing, arg); else if (GET_CODE (outgoing) == PARALLEL) { @@ -4240,7 +6896,7 @@ diddle_return_value (void (*doit) (rtx, void *), void *arg) { rtx x = XEXP (XVECEXP (outgoing, 0, i), 0); - if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER) + if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER) (*doit) (x, arg); } } @@ -4275,7 +6931,7 @@ do_use_return_reg (rtx reg, void *arg ATTRIBUTE_UNUSED) emit_insn (gen_rtx_USE (VOIDmode, reg)); } -static void +void use_return_register (void) { diddle_return_value (do_use_return_reg, NULL); @@ -4291,7 +6947,7 @@ do_warn_unused_parameter (tree fn) decl; decl = TREE_CHAIN (decl)) if (!TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl)) - warning (OPT_Wunused_parameter, "unused parameter %q+D", decl); + warning ("%Junused parameter '%D'", decl, decl); } static GTY(()) rtx initial_trampoline; @@ -4301,13 +6957,67 @@ static GTY(()) rtx initial_trampoline; void expand_function_end (void) { + tree link; rtx clobber_after; + finish_expr_for_function (); + /* If arg_pointer_save_area was referenced only from a nested function, we will not have initialized it yet. Do that now. */ if (arg_pointer_save_area && ! cfun->arg_pointer_save_area_init) get_arg_pointer_save_area (cfun); +#ifdef NON_SAVING_SETJMP + /* Don't put any variables in registers if we call setjmp + on a machine that fails to restore the registers. */ + if (NON_SAVING_SETJMP && current_function_calls_setjmp) + { + if (DECL_INITIAL (current_function_decl) != error_mark_node) + setjmp_protect (DECL_INITIAL (current_function_decl)); + + setjmp_protect_args (); + } +#endif + + /* Initialize any trampolines required by this function. */ + for (link = trampoline_list; link; link = TREE_CHAIN (link)) + { + tree function = TREE_PURPOSE (link); + rtx context ATTRIBUTE_UNUSED = lookup_static_chain (function); + rtx tramp = RTL_EXPR_RTL (TREE_VALUE (link)); +#ifdef TRAMPOLINE_TEMPLATE + rtx blktramp; +#endif + rtx seq; + +#ifdef TRAMPOLINE_TEMPLATE + /* First make sure this compilation has a template for + initializing trampolines. */ + if (initial_trampoline == 0) + { + initial_trampoline + = gen_rtx_MEM (BLKmode, assemble_trampoline_template ()); + set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT); + } +#endif + + /* Generate insns to initialize the trampoline. */ + start_sequence (); + tramp = round_trampoline_addr (XEXP (tramp, 0)); +#ifdef TRAMPOLINE_TEMPLATE + blktramp = replace_equiv_address (initial_trampoline, tramp); + emit_block_move (blktramp, initial_trampoline, + GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); +#endif + trampolines_created = 1; + INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context); + seq = get_insns (); + end_sequence (); + + /* Put those insns at entry to the containing function (this one). */ + emit_insn_before (seq, tail_recursion_reentry); + } + /* If we are doing stack checking and this function makes calls, do a stack probe at the start of the function to ensure we have enough space for another stack frame. */ @@ -4316,14 +7026,14 @@ expand_function_end (void) rtx insn, seq; for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (CALL_P (insn)) + if (GET_CODE (insn) == CALL_INSN) { start_sequence (); probe_stack_range (STACK_CHECK_PROTECT, GEN_INT (STACK_CHECK_MAX_FRAME_SIZE)); seq = get_insns (); end_sequence (); - emit_insn_before (seq, stack_check_probe_note); + emit_insn_before (seq, tail_recursion_reentry); break; } } @@ -4335,13 +7045,30 @@ expand_function_end (void) && !lang_hooks.callgraph.expand_function) do_warn_unused_parameter (current_function_decl); + /* Delete handlers for nonlocal gotos if nothing uses them. */ + if (nonlocal_goto_handler_slots != 0 + && ! current_function_has_nonlocal_label) + delete_handlers (); + /* End any sequences that failed to be closed due to syntax errors. */ while (in_sequence_p ()) end_sequence (); + /* Outside function body, can't compute type's actual size + until next function's body starts. */ + immediate_size_expand--; + clear_pending_stack_adjust (); do_pending_stack_adjust (); + /* ??? This is a kludge. We want to ensure that instructions that + may trap are not moved into the epilogue by scheduling, because + we don't always emit unwind information for the epilogue. + However, not all machine descriptions define a blockage insn, so + emit an ASM_INPUT to act as one. */ + if (flag_non_call_exceptions) + emit_insn (gen_rtx_ASM_INPUT (VOIDmode, "")); + /* Mark the end of the function body. If control reaches this insn, the function can drop through without returning a value. */ @@ -4370,30 +7097,62 @@ expand_function_end (void) is computed. */ clobber_after = get_last_insn (); - /* Output the label for the actual return from the function. */ - emit_label (return_label); + /* Output the label for the actual return from the function, + if one is expected. This happens either because a function epilogue + is used instead of a return instruction, or because a return was done + with a goto in order to run local cleanups, or because of pcc-style + structure returning. */ + if (return_label) + emit_label (return_label); - if (USING_SJLJ_EXCEPTIONS) + if (current_function_instrument_entry_exit) { - /* Let except.c know where it should emit the call to unregister - the function context for sjlj exceptions. */ - if (flag_exceptions) - sjlj_emit_function_exit_after (get_last_insn ()); + rtx fun = DECL_RTL (current_function_decl); + if (GET_CODE (fun) == MEM) + fun = XEXP (fun, 0); + else + abort (); + emit_library_call (profile_function_exit_libfunc, LCT_NORMAL, VOIDmode, + 2, fun, Pmode, + expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, + 0, + hard_frame_pointer_rtx), + Pmode); } - else + +#ifdef TARGET_PROFILER_EPILOGUE + if (current_function_profile && TARGET_PROFILER_EPILOGUE) { - /* @@@ This is a kludge. We want to ensure that instructions that - may trap are not moved into the epilogue by scheduling, because - we don't always emit unwind information for the epilogue. - However, not all machine descriptions define a blockage insn, so - emit an ASM_INPUT to act as one. */ - if (flag_non_call_exceptions) - emit_insn (gen_rtx_ASM_INPUT (VOIDmode, "")); + static rtx mexitcount_libfunc; + static int initialized; + + if (!initialized) + { + mexitcount_libfunc = init_one_libfunc (".mexitcount"); +#if 0 /* Turn this off to prevent erroneous garbage collection. */ + initialized = 1; +#endif + } + emit_library_call (mexitcount_libfunc, LCT_NORMAL, VOIDmode, 0); } +#endif - /* If this is an implementation of throw, do what's necessary to - communicate between __builtin_eh_return and the epilogue. */ - expand_eh_return (); + /* Let except.c know where it should emit the call to unregister + the function context for sjlj exceptions. */ + if (flag_exceptions && USING_SJLJ_EXCEPTIONS) + sjlj_emit_function_exit_after (get_last_insn ()); + + /* If we had calls to alloca, and this machine needs + an accurate stack pointer to exit the function, + insert some code to save and restore the stack pointer. */ + if (! EXIT_IGNORE_STACK + && current_function_calls_alloca) + { + rtx tem = 0; + + emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn); + emit_stack_restore (SAVE_FUNCTION, tem, NULL_RTX); + } /* If scalar return value was computed in a pseudo-reg, or was a named return value that got dumped to the stack, copy that to the hard @@ -4410,7 +7169,8 @@ expand_function_end (void) rtx real_decl_rtl = current_function_return_rtx; /* This should be set in assign_parms. */ - gcc_assert (REG_FUNCTION_VALUE_P (real_decl_rtl)); + if (! REG_FUNCTION_VALUE_P (real_decl_rtl)) + abort (); /* If this is a BLKmode structure being returned in registers, then use the mode computed in expand_return. Note that if @@ -4419,24 +7179,12 @@ expand_function_end (void) if (GET_MODE (real_decl_rtl) == BLKmode) PUT_MODE (real_decl_rtl, GET_MODE (decl_rtl)); - /* If a non-BLKmode return value should be padded at the least - significant end of the register, shift it left by the appropriate - amount. BLKmode results are handled using the group load/store - machinery. */ - if (TYPE_MODE (TREE_TYPE (decl_result)) != BLKmode - && targetm.calls.return_in_msb (TREE_TYPE (decl_result))) - { - emit_move_insn (gen_rtx_REG (GET_MODE (decl_rtl), - REGNO (real_decl_rtl)), - decl_rtl); - shift_return_value (GET_MODE (decl_rtl), true, real_decl_rtl); - } /* If a named return value dumped decl_return to memory, then we may need to re-do the PROMOTE_MODE signed/unsigned extension. */ - else if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl)) + if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl)) { - int unsignedp = TYPE_UNSIGNED (TREE_TYPE (decl_result)); + int unsignedp = TREE_UNSIGNED (TREE_TYPE (decl_result)); if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl))) promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl), @@ -4456,24 +7204,6 @@ expand_function_end (void) TREE_TYPE (decl_result), int_size_in_bytes (TREE_TYPE (decl_result))); } - /* In the case of complex integer modes smaller than a word, we'll - need to generate some non-trivial bitfield insertions. Do that - on a pseudo and not the hard register. */ - else if (GET_CODE (decl_rtl) == CONCAT - && GET_MODE_CLASS (GET_MODE (decl_rtl)) == MODE_COMPLEX_INT - && GET_MODE_BITSIZE (GET_MODE (decl_rtl)) <= BITS_PER_WORD) - { - int old_generating_concat_p; - rtx tmp; - - old_generating_concat_p = generating_concat_p; - generating_concat_p = 0; - tmp = gen_reg_rtx (GET_MODE (decl_rtl)); - generating_concat_p = old_generating_concat_p; - - emit_move_insn (tmp, decl_rtl); - emit_move_insn (real_decl_rtl, tmp); - } else emit_move_insn (real_decl_rtl, decl_rtl); } @@ -4488,17 +7218,17 @@ expand_function_end (void) if (current_function_returns_struct || current_function_returns_pcc_struct) { - rtx value_address = DECL_RTL (DECL_RESULT (current_function_decl)); + rtx value_address + = XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0); tree type = TREE_TYPE (DECL_RESULT (current_function_decl)); - rtx outgoing; - - if (DECL_BY_REFERENCE (DECL_RESULT (current_function_decl))) - type = TREE_TYPE (type); - else - value_address = XEXP (value_address, 0); - - outgoing = targetm.calls.function_value (build_pointer_type (type), - current_function_decl, true); +#ifdef FUNCTION_OUTGOING_VALUE + rtx outgoing + = FUNCTION_OUTGOING_VALUE (build_pointer_type (type), + current_function_decl); +#else + rtx outgoing + = FUNCTION_VALUE (build_pointer_type (type), current_function_decl); +#endif /* Mark this as a function return value so integrate will delete the assignment and USE below when inlining this function. */ @@ -4515,43 +7245,44 @@ expand_function_end (void) current_function_return_rtx = outgoing; } + /* If this is an implementation of throw, do what's necessary to + communicate between __builtin_eh_return and the epilogue. */ + expand_eh_return (); + /* Emit the actual code to clobber return register. */ { - rtx seq; + rtx seq, after; start_sequence (); clobber_return_register (); - expand_naked_return (); seq = get_insns (); end_sequence (); - emit_insn_after (seq, clobber_after); - } - - /* Output the label for the naked return from the function. */ - emit_label (naked_return_label); - - /* If stack protection is enabled for this function, check the guard. */ - if (cfun->stack_protect_guard) - stack_protect_epilogue (); + after = emit_insn_after (seq, clobber_after); - /* If we had calls to alloca, and this machine needs - an accurate stack pointer to exit the function, - insert some code to save and restore the stack pointer. */ - if (! EXIT_IGNORE_STACK - && current_function_calls_alloca) - { - rtx tem = 0; + if (clobber_after != after) + cfun->x_clobber_return_insn = after; + } - emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn); - emit_stack_restore (SAVE_FUNCTION, tem, NULL_RTX); - } + /* Output the label for the naked return from the function, if one is + expected. This is currently used only by __builtin_return. */ + if (naked_return_label) + emit_label (naked_return_label); /* ??? This should no longer be necessary since stupid is no longer with us, but there are some parts of the compiler (eg reload_combine, and sh mach_dep_reorg) that still try and compute their own lifetime info instead of using the general framework. */ use_return_register (); + + /* Fix up any gotos that jumped out to the outermost + binding level of the function. + Must follow emitting RETURN_LABEL. */ + + /* If you have any cleanups to do at this point, + and they need to create temporary variables, + then you will lose. */ + expand_fixups (get_insns ()); } rtx @@ -4578,7 +7309,7 @@ get_arg_pointer_save_area (struct function *f) end_sequence (); push_topmost_sequence (); - emit_insn_after (seq, entry_of_function ()); + emit_insn_after (seq, get_insns ()); pop_topmost_sequence (); } @@ -4589,12 +7320,28 @@ get_arg_pointer_save_area (struct function *f) (a list of one or more insns). */ static void -record_insns (rtx insns, VEC(int,heap) **vecp) +record_insns (rtx insns, varray_type *vecp) { + int i, len; rtx tmp; - for (tmp = insns; tmp != NULL_RTX; tmp = NEXT_INSN (tmp)) - VEC_safe_push (int, heap, *vecp, INSN_UID (tmp)); + tmp = insns; + len = 0; + while (tmp != NULL_RTX) + { + len++; + tmp = NEXT_INSN (tmp); + } + + i = VARRAY_SIZE (*vecp); + VARRAY_GROW (*vecp, i + len); + tmp = insns; + while (tmp != NULL_RTX) + { + VARRAY_INT (*vecp, i) = INSN_UID (tmp); + i++; + tmp = NEXT_INSN (tmp); + } } /* Set the locator of the insn chain starting at INSN to LOC. */ @@ -4613,25 +7360,24 @@ set_insn_locators (rtx insn, int loc) be running after reorg, SEQUENCE rtl is possible. */ static int -contains (rtx insn, VEC(int,heap) **vec) +contains (rtx insn, varray_type vec) { int i, j; - if (NONJUMP_INSN_P (insn) + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) { int count = 0; for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) - for (j = VEC_length (int, *vec) - 1; j >= 0; --j) - if (INSN_UID (XVECEXP (PATTERN (insn), 0, i)) - == VEC_index (int, *vec, j)) + for (j = VARRAY_SIZE (vec) - 1; j >= 0; --j) + if (INSN_UID (XVECEXP (PATTERN (insn), 0, i)) == VARRAY_INT (vec, j)) count++; return count; } else { - for (j = VEC_length (int, *vec) - 1; j >= 0; --j) - if (INSN_UID (insn) == VEC_index (int, *vec, j)) + for (j = VARRAY_SIZE (vec) - 1; j >= 0; --j) + if (INSN_UID (insn) == VARRAY_INT (vec, j)) return 1; } return 0; @@ -4640,9 +7386,9 @@ contains (rtx insn, VEC(int,heap) **vec) int prologue_epilogue_contains (rtx insn) { - if (contains (insn, &prologue)) + if (contains (insn, prologue)) return 1; - if (contains (insn, &epilogue)) + if (contains (insn, epilogue)) return 1; return 0; } @@ -4651,7 +7397,7 @@ int sibcall_epilogue_contains (rtx insn) { if (sibcall_epilogue) - return contains (insn, &sibcall_epilogue); + return contains (insn, sibcall_epilogue); return 0; } @@ -4670,35 +7416,34 @@ emit_return_into_block (basic_block bb, rtx line_note) #if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX) -/* These functions convert the epilogue into a variant that does not - modify the stack pointer. This is used in cases where a function - returns an object whose size is not known until it is computed. - The called function leaves the object on the stack, leaves the - stack depressed, and returns a pointer to the object. - - What we need to do is track all modifications and references to the - stack pointer, deleting the modifications and changing the - references to point to the location the stack pointer would have - pointed to had the modifications taken place. - - These functions need to be portable so we need to make as few - assumptions about the epilogue as we can. However, the epilogue - basically contains three things: instructions to reset the stack - pointer, instructions to reload registers, possibly including the - frame pointer, and an instruction to return to the caller. - - We must be sure of what a relevant epilogue insn is doing. We also - make no attempt to validate the insns we make since if they are - invalid, we probably can't do anything valid. The intent is that - these routines get "smarter" as more and more machines start to use - them and they try operating on different epilogues. - - We use the following structure to track what the part of the - epilogue that we've already processed has done. We keep two copies - of the SP equivalence, one for use during the insn we are - processing and one for use in the next insn. The difference is - because one part of a PARALLEL may adjust SP and the other may use - it. */ +/* These functions convert the epilogue into a variant that does not modify the + stack pointer. This is used in cases where a function returns an object + whose size is not known until it is computed. The called function leaves the + object on the stack, leaves the stack depressed, and returns a pointer to + the object. + + What we need to do is track all modifications and references to the stack + pointer, deleting the modifications and changing the references to point to + the location the stack pointer would have pointed to had the modifications + taken place. + + These functions need to be portable so we need to make as few assumptions + about the epilogue as we can. However, the epilogue basically contains + three things: instructions to reset the stack pointer, instructions to + reload registers, possibly including the frame pointer, and an + instruction to return to the caller. + + If we can't be sure of what a relevant epilogue insn is doing, we abort. + We also make no attempt to validate the insns we make since if they are + invalid, we probably can't do anything valid. The intent is that these + routines get "smarter" as more and more machines start to use them and + they try operating on different epilogues. + + We use the following structure to track what the part of the epilogue that + we've already processed has done. We keep two copies of the SP equivalence, + one for use during the insn we are processing and one for use in the next + insn. The difference is because one part of a PARALLEL may adjust SP + and the other may use it. */ struct epi_info { @@ -4783,34 +7528,26 @@ keep_stack_depressed (rtx insns) unchanged. Otherwise, it must be a MEM and we see what the base register and offset are. In any case, we have to emit any pending load to the equivalent reg of SP, if any. */ - if (REG_P (retaddr)) + if (GET_CODE (retaddr) == REG) { emit_equiv_load (&info); add_insn (insn); insn = next; continue; } - else + else if (GET_CODE (retaddr) == MEM + && GET_CODE (XEXP (retaddr, 0)) == REG) + base = gen_rtx_REG (Pmode, REGNO (XEXP (retaddr, 0))), offset = 0; + else if (GET_CODE (retaddr) == MEM + && GET_CODE (XEXP (retaddr, 0)) == PLUS + && GET_CODE (XEXP (XEXP (retaddr, 0), 0)) == REG + && GET_CODE (XEXP (XEXP (retaddr, 0), 1)) == CONST_INT) { - rtx ret_ptr; - gcc_assert (MEM_P (retaddr)); - - ret_ptr = XEXP (retaddr, 0); - - if (REG_P (ret_ptr)) - { - base = gen_rtx_REG (Pmode, REGNO (ret_ptr)); - offset = 0; - } - else - { - gcc_assert (GET_CODE (ret_ptr) == PLUS - && REG_P (XEXP (ret_ptr, 0)) - && GET_CODE (XEXP (ret_ptr, 1)) == CONST_INT); - base = gen_rtx_REG (Pmode, REGNO (XEXP (ret_ptr, 0))); - offset = INTVAL (XEXP (ret_ptr, 1)); - } + base = gen_rtx_REG (Pmode, REGNO (XEXP (XEXP (retaddr, 0), 0))); + offset = INTVAL (XEXP (XEXP (retaddr, 0), 1)); } + else + abort (); /* If the base of the location containing the return pointer is SP, we must update it with the replacement address. Otherwise, @@ -4822,7 +7559,6 @@ keep_stack_depressed (rtx insns) info.sp_offset)); retaddr = gen_rtx_MEM (Pmode, retaddr); - MEM_NOTRAP_P (retaddr) = 1; /* If there is a pending load to the equivalent register for SP and we reference that register, we must load our address into @@ -4837,16 +7573,17 @@ keep_stack_depressed (rtx insns) if (HARD_REGNO_MODE_OK (regno, Pmode) && !fixed_regs[regno] && TEST_HARD_REG_BIT (regs_invalidated_by_call, regno) - && !REGNO_REG_SET_P - (EXIT_BLOCK_PTR->il.rtl->global_live_at_start, regno) + && !REGNO_REG_SET_P (EXIT_BLOCK_PTR->global_live_at_start, + regno) && !refers_to_regno_p (regno, - regno + hard_regno_nregs[regno] - [Pmode], + regno + HARD_REGNO_NREGS (regno, + Pmode), info.equiv_reg_src, NULL) && info.const_equiv[regno] == 0) break; - gcc_assert (regno < FIRST_PSEUDO_REGISTER); + if (regno == FIRST_PSEUDO_REGISTER) + abort (); reg = gen_rtx_REG (Pmode, regno); emit_move_insn (reg, retaddr); @@ -4858,8 +7595,10 @@ keep_stack_depressed (rtx insns) /* Show the SET in the above insn is a RETURN. */ jump_set = single_set (jump_insn); - gcc_assert (jump_set); - SET_IS_RETURN_P (jump_set) = 1; + if (jump_set == 0) + abort (); + else + SET_IS_RETURN_P (jump_set) = 1; } /* If SP is not mentioned in the pattern and its equivalent register, if @@ -4874,13 +7613,11 @@ keep_stack_depressed (rtx insns) && (info.sp_equiv_reg == stack_pointer_rtx || !reg_set_p (info.sp_equiv_reg, insn))) { - int changed; - - changed = validate_replace_rtx (stack_pointer_rtx, - plus_constant (info.sp_equiv_reg, - info.sp_offset), - insn); - gcc_assert (changed); + if (! validate_replace_rtx (stack_pointer_rtx, + plus_constant (info.sp_equiv_reg, + info.sp_offset), + insn)) + abort (); add_insn (insn); } @@ -4917,25 +7654,24 @@ static void handle_epilogue_set (rtx set, struct epi_info *p) { /* First handle the case where we are setting SP. Record what it is being - set from, which we must be able to determine */ + set from. If unknown, abort. */ if (reg_set_p (stack_pointer_rtx, set)) { - gcc_assert (SET_DEST (set) == stack_pointer_rtx); + if (SET_DEST (set) != stack_pointer_rtx) + abort (); if (GET_CODE (SET_SRC (set)) == PLUS) { p->new_sp_equiv_reg = XEXP (SET_SRC (set), 0); if (GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT) p->new_sp_offset = INTVAL (XEXP (SET_SRC (set), 1)); + else if (GET_CODE (XEXP (SET_SRC (set), 1)) == REG + && REGNO (XEXP (SET_SRC (set), 1)) < FIRST_PSEUDO_REGISTER + && p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))] != 0) + p->new_sp_offset + = INTVAL (p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]); else - { - gcc_assert (REG_P (XEXP (SET_SRC (set), 1)) - && (REGNO (XEXP (SET_SRC (set), 1)) - < FIRST_PSEUDO_REGISTER) - && p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]); - p->new_sp_offset - = INTVAL (p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]); - } + abort (); } else p->new_sp_equiv_reg = SET_SRC (set), p->new_sp_offset = 0; @@ -4947,31 +7683,33 @@ handle_epilogue_set (rtx set, struct epi_info *p) p->new_sp_offset += p->sp_offset; } - gcc_assert (p->new_sp_equiv_reg && REG_P (p->new_sp_equiv_reg)); + if (p->new_sp_equiv_reg == 0 || GET_CODE (p->new_sp_equiv_reg) != REG) + abort (); return; } - /* Next handle the case where we are setting SP's equivalent - register. We must not already have a value to set it to. We - could update, but there seems little point in handling that case. - Note that we have to allow for the case where we are setting the - register set in the previous part of a PARALLEL inside a single - insn. But use the old offset for any updates within this insn. - We must allow for the case where the register is being set in a - different (usually wider) mode than Pmode). */ + /* Next handle the case where we are setting SP's equivalent register. + If we already have a value to set it to, abort. We could update, but + there seems little point in handling that case. Note that we have + to allow for the case where we are setting the register set in + the previous part of a PARALLEL inside a single insn. But use the + old offset for any updates within this insn. We must allow for the case + where the register is being set in a different (usually wider) mode than + Pmode). */ else if (p->new_sp_equiv_reg != 0 && reg_set_p (p->new_sp_equiv_reg, set)) { - gcc_assert (!p->equiv_reg_src - && REG_P (p->new_sp_equiv_reg) - && REG_P (SET_DEST (set)) - && (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) - <= BITS_PER_WORD) - && REGNO (p->new_sp_equiv_reg) == REGNO (SET_DEST (set))); - p->equiv_reg_src - = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx, - plus_constant (p->sp_equiv_reg, - p->sp_offset)); + if (p->equiv_reg_src != 0 + || GET_CODE (p->new_sp_equiv_reg) != REG + || GET_CODE (SET_DEST (set)) != REG + || GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) > BITS_PER_WORD + || REGNO (p->new_sp_equiv_reg) != REGNO (SET_DEST (set))) + abort (); + else + p->equiv_reg_src + = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx, + plus_constant (p->sp_equiv_reg, + p->sp_offset)); } /* Otherwise, replace any references to SP in the insn to its new value @@ -4994,37 +7732,14 @@ static void update_epilogue_consts (rtx dest, rtx x, void *data) { struct epi_info *p = (struct epi_info *) data; - rtx new; - if (!REG_P (dest) || REGNO (dest) >= FIRST_PSEUDO_REGISTER) + if (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER) return; - - /* If we are either clobbering a register or doing a partial set, - show we don't know the value. */ - else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x))) + else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x)) + || GET_CODE (SET_SRC (x)) != CONST_INT) p->const_equiv[REGNO (dest)] = 0; - - /* If we are setting it to a constant, record that constant. */ - else if (GET_CODE (SET_SRC (x)) == CONST_INT) - p->const_equiv[REGNO (dest)] = SET_SRC (x); - - /* If this is a binary operation between a register we have been tracking - and a constant, see if we can compute a new constant value. */ - else if (ARITHMETIC_P (SET_SRC (x)) - && REG_P (XEXP (SET_SRC (x), 0)) - && REGNO (XEXP (SET_SRC (x), 0)) < FIRST_PSEUDO_REGISTER - && p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))] != 0 - && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT - && 0 != (new = simplify_binary_operation - (GET_CODE (SET_SRC (x)), GET_MODE (dest), - p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))], - XEXP (SET_SRC (x), 1))) - && GET_CODE (new) == CONST_INT) - p->const_equiv[REGNO (dest)] = new; - - /* Otherwise, we can't do anything with this value. */ else - p->const_equiv[REGNO (dest)] = 0; + p->const_equiv[REGNO (dest)] = SET_SRC (x); } /* Emit an insn to do the load shown in p->equiv_reg_src, if needed. */ @@ -5064,7 +7779,6 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) #if defined (HAVE_epilogue) || defined(HAVE_return) rtx epilogue_end = NULL_RTX; #endif - edge_iterator ei; #ifdef HAVE_prologue if (HAVE_prologue) @@ -5084,16 +7798,17 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) /* Can't deal with multiple successors of the entry block at the moment. Function should always have at least one entry point. */ - gcc_assert (single_succ_p (ENTRY_BLOCK_PTR)); + if (!ENTRY_BLOCK_PTR->succ || ENTRY_BLOCK_PTR->succ->succ_next) + abort (); - insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR)); + insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ); inserted = 1; } #endif /* If the exit block has no non-fake predecessors, we don't need an epilogue. */ - FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) if ((e->flags & EDGE_FAKE) == 0) break; if (e == NULL) @@ -5109,9 +7824,10 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) emit (conditional) return instructions. */ basic_block last; + edge e_next; rtx label; - FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) if (e->flags & EDGE_FALLTHRU) break; if (e == NULL) @@ -5120,16 +7836,15 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) /* Verify that there are no active instructions in the last block. */ label = BB_END (last); - while (label && !LABEL_P (label)) + while (label && GET_CODE (label) != CODE_LABEL) { if (active_insn_p (label)) break; label = PREV_INSN (label); } - if (BB_HEAD (last) == label && LABEL_P (label)) + if (BB_HEAD (last) == label && GET_CODE (label) == CODE_LABEL) { - edge_iterator ei2; rtx epilogue_line_note = NULL_RTX; /* Locate the line number associated with the closing brace, @@ -5137,29 +7852,24 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) for (seq = get_last_insn (); seq && ! active_insn_p (seq); seq = PREV_INSN (seq)) - if (NOTE_P (seq) && NOTE_LINE_NUMBER (seq) > 0) + if (GET_CODE (seq) == NOTE && NOTE_LINE_NUMBER (seq) > 0) { epilogue_line_note = seq; break; } - for (ei2 = ei_start (last->preds); (e = ei_safe_edge (ei2)); ) + for (e = last->pred; e; e = e_next) { basic_block bb = e->src; rtx jump; + e_next = e->pred_next; if (bb == ENTRY_BLOCK_PTR) - { - ei_next (&ei2); - continue; - } + continue; jump = BB_END (bb); - if (!JUMP_P (jump) || JUMP_LABEL (jump) != label) - { - ei_next (&ei2); - continue; - } + if ((GET_CODE (jump) != JUMP_INSN) || JUMP_LABEL (jump) != label) + continue; /* If we have an unconditional jump, we can replace that with a simple return instruction. */ @@ -5174,25 +7884,16 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) else if (condjump_p (jump)) { if (! redirect_jump (jump, 0, 0)) - { - ei_next (&ei2); - continue; - } + continue; /* If this block has only one successor, it both jumps and falls through to the fallthru block, so we can't delete the edge. */ - if (single_succ_p (bb)) - { - ei_next (&ei2); - continue; - } + if (bb->succ->succ_next == NULL) + continue; } else - { - ei_next (&ei2); - continue; - } + continue; /* Fix up the CFG for the successful change we just made. */ redirect_edge_succ (e, EXIT_BLOCK_PTR); @@ -5204,25 +7905,25 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) emit_barrier_after (BB_END (last)); emit_return_into_block (last, epilogue_line_note); epilogue_end = BB_END (last); - single_succ_edge (last)->flags &= ~EDGE_FALLTHRU; + last->succ->flags &= ~EDGE_FALLTHRU; goto epilogue_done; } } #endif - /* Find the edge that falls through to EXIT. Other edges may exist - due to RETURN instructions, but those don't need epilogues. - There really shouldn't be a mixture -- either all should have - been converted or none, however... */ - - FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) - if (e->flags & EDGE_FALLTHRU) - break; - if (e == NULL) - goto epilogue_done; - #ifdef HAVE_epilogue if (HAVE_epilogue) { + /* Find the edge that falls through to EXIT. Other edges may exist + due to RETURN instructions, but those don't need epilogues. + There really shouldn't be a mixture -- either all should have + been converted or none, however... */ + + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) + if (e->flags & EDGE_FALLTHRU) + break; + if (e == NULL) + goto epilogue_done; + start_sequence (); epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG); @@ -5248,27 +7949,7 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) insert_insn_on_edge (seq, e); inserted = 1; } - else #endif - { - basic_block cur_bb; - - if (! next_active_insn (BB_END (e->src))) - goto epilogue_done; - /* We have a fall-through edge to the exit block, the source is not - at the end of the function, and there will be an assembler epilogue - at the end of the function. - We can't use force_nonfallthru here, because that would try to - use return. Inserting a jump 'by hand' is extremely messy, so - we take advantage of cfg_layout_finalize using - fixup_fallthru_exit_predecessor. */ - cfg_layout_initialize (0); - FOR_EACH_BB (cur_bb) - if (cur_bb->index >= NUM_FIXED_BLOCKS - && cur_bb->next_bb->index >= NUM_FIXED_BLOCKS) - cur_bb->aux = cur_bb->next_bb; - cfg_layout_finalize (); - } epilogue_done: if (inserted) @@ -5276,17 +7957,16 @@ epilogue_done: #ifdef HAVE_sibcall_epilogue /* Emit sibling epilogues before any sibling call sites. */ - for (ei = ei_start (EXIT_BLOCK_PTR->preds); (e = ei_safe_edge (ei)); ) + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) { basic_block bb = e->src; rtx insn = BB_END (bb); + rtx i; + rtx newinsn; - if (!CALL_P (insn) + if (GET_CODE (insn) != CALL_INSN || ! SIBLING_CALL_P (insn)) - { - ei_next (&ei); - continue; - } + continue; start_sequence (); emit_insn (gen_sibcall_epilogue ()); @@ -5299,8 +7979,8 @@ epilogue_done: record_insns (seq, &sibcall_epilogue); set_insn_locators (seq, epilogue_locator); - emit_insn_before (seq, insn); - ei_next (&ei); + i = PREV_INSN (insn); + newinsn = emit_insn_before (seq, insn); } #endif @@ -5326,7 +8006,7 @@ epilogue_done: for (insn = prologue_end; insn; insn = prev) { prev = PREV_INSN (insn); - if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0) + if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) { /* Note that we cannot reorder the first insn in the chain, since rest_of_compilation relies on that @@ -5341,7 +8021,7 @@ epilogue_done: for (insn = BB_END (ENTRY_BLOCK_PTR->next_bb); insn != prologue_end && insn; insn = PREV_INSN (insn)) - if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0) + if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) break; /* If we didn't find one, make a copy of the first line number @@ -5351,7 +8031,7 @@ epilogue_done: for (insn = next_active_insn (prologue_end); insn; insn = PREV_INSN (insn)) - if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0) + if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) { emit_note_copy_after (insn, prologue_end); break; @@ -5372,7 +8052,7 @@ epilogue_done: for (insn = epilogue_end; insn; insn = next) { next = NEXT_INSN (insn); - if (NOTE_P (insn) + if (GET_CODE (insn) == NOTE && (NOTE_LINE_NUMBER (insn) > 0 || NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG || NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END)) @@ -5392,7 +8072,7 @@ reposition_prologue_and_epilogue_notes (rtx f ATTRIBUTE_UNUSED) rtx insn, last, note; int len; - if ((len = VEC_length (int, prologue)) > 0) + if ((len = VARRAY_SIZE (prologue)) > 0) { last = 0, note = 0; @@ -5401,12 +8081,12 @@ reposition_prologue_and_epilogue_notes (rtx f ATTRIBUTE_UNUSED) reorg has run. */ for (insn = f; insn; insn = NEXT_INSN (insn)) { - if (NOTE_P (insn)) + if (GET_CODE (insn) == NOTE) { if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END) note = insn; } - else if (contains (insn, &prologue)) + else if (contains (insn, prologue)) { last = insn; if (--len == 0) @@ -5421,19 +8101,19 @@ reposition_prologue_and_epilogue_notes (rtx f ATTRIBUTE_UNUSED) if (note == 0) { for (note = last; (note = NEXT_INSN (note));) - if (NOTE_P (note) + if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END) break; } /* Avoid placing note between CODE_LABEL and BASIC_BLOCK note. */ - if (LABEL_P (last)) + if (GET_CODE (last) == CODE_LABEL) last = NEXT_INSN (last); reorder_insns (note, note, last); } } - if ((len = VEC_length (int, epilogue)) > 0) + if ((len = VARRAY_SIZE (epilogue)) > 0) { last = 0, note = 0; @@ -5442,12 +8122,12 @@ reposition_prologue_and_epilogue_notes (rtx f ATTRIBUTE_UNUSED) reorg has run. */ for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) { - if (NOTE_P (insn)) + if (GET_CODE (insn) == NOTE) { if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG) note = insn; } - else if (contains (insn, &epilogue)) + else if (contains (insn, epilogue)) { last = insn; if (--len == 0) @@ -5462,7 +8142,7 @@ reposition_prologue_and_epilogue_notes (rtx f ATTRIBUTE_UNUSED) if (note == 0) { for (note = insn; (note = PREV_INSN (note));) - if (NOTE_P (note) + if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) == NOTE_INSN_EPILOGUE_BEG) break; } @@ -5474,124 +8154,21 @@ reposition_prologue_and_epilogue_notes (rtx f ATTRIBUTE_UNUSED) #endif /* HAVE_prologue or HAVE_epilogue */ } -/* Resets insn_block_boundaries array. */ - -void -reset_block_changes (void) -{ - cfun->ib_boundaries_block = VEC_alloc (tree, gc, 100); - VEC_quick_push (tree, cfun->ib_boundaries_block, NULL_TREE); -} - -/* Record the boundary for BLOCK. */ -void -record_block_change (tree block) -{ - int i, n; - tree last_block; - - if (!block) - return; - - if(!cfun->ib_boundaries_block) - return; - - last_block = VEC_pop (tree, cfun->ib_boundaries_block); - n = get_max_uid (); - for (i = VEC_length (tree, cfun->ib_boundaries_block); i < n; i++) - VEC_safe_push (tree, gc, cfun->ib_boundaries_block, last_block); - - VEC_safe_push (tree, gc, cfun->ib_boundaries_block, block); -} - -/* Finishes record of boundaries. */ -void -finalize_block_changes (void) -{ - record_block_change (DECL_INITIAL (current_function_decl)); -} - -/* For INSN return the BLOCK it belongs to. */ -void -check_block_change (rtx insn, tree *block) -{ - unsigned uid = INSN_UID (insn); - - if (uid >= VEC_length (tree, cfun->ib_boundaries_block)) - return; - - *block = VEC_index (tree, cfun->ib_boundaries_block, uid); -} +/* Called once, at initialization, to initialize function.c. */ -/* Releases the ib_boundaries_block records. */ void -free_block_changes (void) +init_function_once (void) { - VEC_free (tree, gc, cfun->ib_boundaries_block); + VARRAY_INT_INIT (prologue, 0, "prologue"); + VARRAY_INT_INIT (epilogue, 0, "epilogue"); + VARRAY_INT_INIT (sibcall_epilogue, 0, "sibcall_epilogue"); } /* Returns the name of the current function. */ const char * current_function_name (void) { - return lang_hooks.decl_printable_name (cfun->decl, 2); -} - - -static unsigned int -rest_of_handle_check_leaf_regs (void) -{ -#ifdef LEAF_REGISTERS - current_function_uses_only_leaf_regs - = optimize > 0 && only_leaf_regs_used () && leaf_function_p (); -#endif - return 0; -} - -/* Insert a TYPE into the used types hash table of CFUN. */ -static void -used_types_insert_helper (tree type, struct function *func) -{ - if (type != NULL && func != NULL) - { - void **slot; - - if (func->used_types_hash == NULL) - func->used_types_hash = htab_create_ggc (37, htab_hash_pointer, - htab_eq_pointer, NULL); - slot = htab_find_slot (func->used_types_hash, type, INSERT); - if (*slot == NULL) - *slot = type; - } + return (*lang_hooks.decl_printable_name) (cfun->decl, 2); } -/* Given a type, insert it into the used hash table in cfun. */ -void -used_types_insert (tree t) -{ - while (POINTER_TYPE_P (t) || TREE_CODE (t) == ARRAY_TYPE) - t = TREE_TYPE (t); - t = TYPE_MAIN_VARIANT (t); - if (debug_info_level > DINFO_LEVEL_NONE) - used_types_insert_helper (t, cfun); -} - -struct tree_opt_pass pass_leaf_regs = -{ - NULL, /* name */ - NULL, /* gate */ - rest_of_handle_check_leaf_regs, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - 0, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ - 0 /* letter */ -}; - - #include "gt-function.h" diff --git a/contrib/gcc/gcc.c b/contrib/gcc/gcc.c index 0b5ee4b..2800d91 100644 --- a/contrib/gcc/gcc.c +++ b/contrib/gcc/gcc.c @@ -1,5 +1,6 @@ /* Compiler driver program that can handle many languages. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. @@ -17,12 +18,14 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. This paragraph is here to try to keep Sun CC from dying. The number of chars here seems crucial!!!! */ +/* $FreeBSD$ */ + /* This program is the user interface to the C compiler and possibly to other compilers. It is used because compilation is a complicated procedure which involves running several programs and passing temporary files between @@ -59,7 +62,7 @@ compilation is specified by a string called a "spec". */ 4. If the argument takes an argument, e.g., `--baz argument1', modify either DEFAULT_SWITCH_TAKES_ARG or - DEFAULT_WORD_SWITCH_TAKES_ARG in gcc.h. Omit the first `-' + DEFAULT_WORD_SWITCH_TAKES_ARG in this file. Omit the first `-' from `--baz'. 5. Document the option in this file's display_help(). If the @@ -80,13 +83,18 @@ compilation is specified by a string called a "spec". */ #if ! defined( SIGCHLD ) && defined( SIGCLD ) # define SIGCHLD SIGCLD #endif -#include "xregex.h" #include "obstack.h" #include "intl.h" #include "prefix.h" #include "gcc.h" #include "flags.h" -#include "opts.h" + +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#if defined (HAVE_DECL_GETRUSAGE) && !HAVE_DECL_GETRUSAGE +extern int getrusage (int, struct rusage *); +#endif /* By default there is no special suffix for target executables. */ /* FIXME: when autoconf is fixed, remove the host check - dj */ @@ -214,10 +222,6 @@ static const char *target_sysroot_hdrs_suffix = 0; static int save_temps_flag; -/* Nonzero means pass multiple source files to the compiler at one time. */ - -static int combine_flag = 0; - /* Nonzero means use pipes to communicate between subprocesses. Overridden by either of the above two flags. */ @@ -278,9 +282,14 @@ static struct obstack obstack; static struct obstack collect_obstack; +/* These structs are used to collect resource usage information for + subprocesses. */ +#ifdef HAVE_GETRUSAGE +static struct rusage rus, prus; +#endif + /* Forward declaration for prototypes. */ struct path_prefix; -struct prefix_list; static void init_spec (void); static void store_arg (const char *, int, int); @@ -288,16 +297,14 @@ static char *load_specs (const char *); static void read_specs (const char *, int); static void set_spec (const char *, const char *); static struct compiler *lookup_compiler (const char *, size_t, const char *); -static char *build_search_list (const struct path_prefix *, const char *, - bool, bool); -static void putenv_from_prefixes (const struct path_prefix *, const char *, - bool); +static char *build_search_list (struct path_prefix *, const char *, int); +static void putenv_from_prefixes (struct path_prefix *, const char *); static int access_check (const char *, int); -static char *find_a_file (const struct path_prefix *, const char *, int, bool); +static char *find_a_file (struct path_prefix *, const char *, int, int); static void add_prefix (struct path_prefix *, const char *, const char *, - int, int, int); + int, int, int *, int); static void add_sysrooted_prefix (struct path_prefix *, const char *, - const char *, int, int, int); + const char *, int, int, int *, int); static void translate_options (int *, const char *const **); static char *skip_whitespace (char *); static void delete_if_ordinary (const char *); @@ -321,7 +328,7 @@ static int do_spec_2 (const char *); static void do_option_spec (const char *, const char *); static void do_self_spec (const char *); static const char *find_file (const char *); -static int is_directory (const char *, bool); +static int is_directory (const char *, const char *, int); static const char *validate_switches (const char *); static void validate_all_switches (void); static inline void validate_switches_from_spec (const char *); @@ -331,7 +338,7 @@ static int default_arg (const char *, int); static void set_multilib_dir (void); static void print_multilib_info (void); static void perror_with_name (const char *); -static void fatal_ice (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN; +static void pfatal_pexecute (const char *, const char *) ATTRIBUTE_NORETURN; static void notice (const char *, ...) ATTRIBUTE_PRINTF_1; static void display_help (void); static void add_preprocessor_option (const char *, int); @@ -342,7 +349,7 @@ static int execute (void); static void alloc_args (void); static void clear_args (void); static void fatal_error (int); -#if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC) +#ifdef ENABLE_SHARED_LIBGCC static void init_gcc_specs (struct obstack *, const char *, const char *, const char *); #endif @@ -352,9 +359,6 @@ static const char *convert_filename (const char *, int, int); static const char *if_exists_spec_function (int, const char **); static const char *if_exists_else_spec_function (int, const char **); -static const char *replace_outfile_spec_function (int, const char **); -static const char *version_compare_spec_function (int, const char **); -static const char *include_spec_function (int, const char **); /* The Specs Language @@ -384,7 +388,7 @@ or with constant text in a single argument. chosen in a way that is hard to predict even when previously chosen file names are known. For example, `%g.s ... %g.o ... %g.s' might turn into `ccUVUUAU.s ccXYAXZ12.o ccUVUUAU.s'. SUFFIX matches - the regexp "[.0-9A-Za-z]*%O"; "%O" is treated exactly as if it + the regexp "[.A-Za-z]*%O"; "%O" is treated exactly as if it had been pre-processed. Previously, %g was simply substituted with a file name chosen once per compilation, without regard to any appended suffix (which was therefore treated just like @@ -443,8 +447,8 @@ or with constant text in a single argument. SUFFIX characters following %O as they would following, for example, `.o'. %I Substitute any of -iprefix (made from GCC_EXEC_PREFIX), -isysroot - (made from TARGET_SYSTEM_ROOT), -isystem (made from COMPILER_PATH - and -B options) and -imultilib as necessary. + (made from TARGET_SYSTEM_ROOT), and -isystem (made from COMPILER_PATH + and -B options) as necessary. %s current argument is the name of a library or startup file of some sort. Search for that file in a standard list of directories and substitute the full name found. @@ -465,8 +469,8 @@ or with constant text in a single argument. %l process LINK_SPEC as a spec. %L process LIB_SPEC as a spec. %G process LIBGCC_SPEC as a spec. - %R Output the concatenation of target_system_root and - target_sysroot_suffix. + %M output multilib_dir with directory separators replaced with "_"; + if multilib_dir is not set or is ".", output "". %S process STARTFILE_SPEC as a spec. A capital S is actually used here. %E process ENDFILE_SPEC as a spec. A capital E is actually used here. %C process CPP_SPEC as a spec. @@ -595,26 +599,10 @@ proper position among the other output files. */ #define LIB_SPEC "%{!shared:%{g*:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}" #endif -/* mudflap specs */ -#ifndef MFWRAP_SPEC -/* XXX: valid only for GNU ld */ -/* XXX: should exactly match hooks provided by libmudflap.a */ -#define MFWRAP_SPEC " %{static: %{fmudflap|fmudflapth: \ - --wrap=malloc --wrap=free --wrap=calloc --wrap=realloc\ - --wrap=mmap --wrap=munmap --wrap=alloca\ -} %{fmudflapth: --wrap=pthread_create\ -}} %{fmudflap|fmudflapth: --wrap=main}" -#endif -#ifndef MFLIB_SPEC -#define MFLIB_SPEC "%{fmudflap|fmudflapth: -export-dynamic}" -#endif - /* config.h can define LIBGCC_SPEC to override how and when libgcc.a is included. */ #ifndef LIBGCC_SPEC -#if defined(REAL_LIBGCC_SPEC) -#define LIBGCC_SPEC REAL_LIBGCC_SPEC -#elif defined(LINK_LIBGCC_SPECIAL_1) +#if defined(LINK_LIBGCC_SPECIAL) || defined(LINK_LIBGCC_SPECIAL_1) /* Have gcc do the search for libgcc.a. */ #define LIBGCC_SPEC "libgcc.a%s" #else @@ -674,14 +662,6 @@ proper position among the other output files. */ #define LINK_GCC_C_SEQUENCE_SPEC "%G %L %G" #endif -#ifndef LINK_SSP_SPEC -#ifdef TARGET_LIBC_PROVIDES_SSP -#define LINK_SSP_SPEC "%{fstack-protector:}" -#else -#define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all:-lssp_nonshared -lssp}" -#endif -#endif - #ifndef LINK_PIE_SPEC #ifdef HAVE_LD_PIE #define LINK_PIE_SPEC "%{pie:-pie} " @@ -701,26 +681,25 @@ proper position among the other output files. */ %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\ %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\ %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\ - %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\ - %{fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\ - %{fprofile-arcs|fprofile-generate|coverage:-lgcov}\ - %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\ + %{static:} %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate:-lgcov}\ + %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}}\ %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}" #endif #ifndef LINK_LIBGCC_SPEC -/* Generate -L options for startfile prefix list. */ -# define LINK_LIBGCC_SPEC "%D" +# ifdef LINK_LIBGCC_SPECIAL +/* Don't generate -L options for startfile prefix list. */ +# define LINK_LIBGCC_SPEC "" +# else +/* Do generate them. */ +# define LINK_LIBGCC_SPEC "%D" +# endif #endif #ifndef STARTFILE_PREFIX_SPEC # define STARTFILE_PREFIX_SPEC "" #endif -#ifndef SYSROOT_SPEC -# define SYSROOT_SPEC "--sysroot=%R" -#endif - #ifndef SYSROOT_SUFFIX_SPEC # define SYSROOT_SUFFIX_SPEC "" #endif @@ -734,14 +713,10 @@ static const char *cpp_spec = CPP_SPEC; static const char *cc1_spec = CC1_SPEC; static const char *cc1plus_spec = CC1PLUS_SPEC; static const char *link_gcc_c_sequence_spec = LINK_GCC_C_SEQUENCE_SPEC; -static const char *link_ssp_spec = LINK_SSP_SPEC; static const char *asm_spec = ASM_SPEC; static const char *asm_final_spec = ASM_FINAL_SPEC; static const char *link_spec = LINK_SPEC; static const char *lib_spec = LIB_SPEC; -static const char *mfwrap_spec = MFWRAP_SPEC; -static const char *mflib_spec = MFLIB_SPEC; -static const char *link_gomp_spec = ""; static const char *libgcc_spec = LIBGCC_SPEC; static const char *endfile_spec = ENDFILE_SPEC; static const char *startfile_spec = STARTFILE_SPEC; @@ -750,7 +725,6 @@ static const char *linker_name_spec = LINKER_NAME; static const char *link_command_spec = LINK_COMMAND_SPEC; static const char *link_libgcc_spec = LINK_LIBGCC_SPEC; static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC; -static const char *sysroot_spec = SYSROOT_SPEC; static const char *sysroot_suffix_spec = SYSROOT_SUFFIX_SPEC; static const char *sysroot_hdrs_suffix_spec = SYSROOT_HEADERS_SUFFIX_SPEC; @@ -771,14 +745,12 @@ static const char *trad_capable_cpp = file that happens to exist is up-to-date. */ static const char *cpp_unique_options = "%{C|CC:%{!E:%eGCC does not support -C or -CC without -E}}\ - %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I\ + %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*} %{P} %I\ %{MD:-MD %{!o:%b.d}%{o*:%.d%*}}\ %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}}\ %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\ %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}}\ %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i\ - %{fmudflap:-D_MUDFLAP -include mf-runtime.h}\ - %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h}\ %{E|M|MM:%W{o*}}"; /* This contains cpp options which are common with cc1_options and are passed @@ -789,7 +761,7 @@ static const char *cpp_unique_options = static const char *cpp_options = "%(cpp_unique_options) %1 %{m*} %{std*&ansi&trigraphs} %{W*&pedantic*} %{w}\ %{f*} %{g*:%{!g0:%{!fno-working-directory:-fworking-directory}}} %{O*}\ - %{undef} %{save-temps:-fpch-preprocess}"; + %{undef}"; /* This contains cpp options which are not passed when the preprocessor output will be used by another program. */ @@ -805,9 +777,7 @@ static const char *cc1_options = %{Qn:-fno-ident} %{--help:--help}\ %{--target-help:--target-help}\ %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\ - %{fsyntax-only:-o %j} %{-param*}\ - %{fmudflap|fmudflapth:-fno-builtin -fno-merge-constants}\ - %{coverage:-fprofile-arcs -ftest-coverage}"; + %{fsyntax-only:-o %j} %{-param*}"; static const char *asm_options = "%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}"; @@ -840,15 +810,7 @@ static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS; #define DRIVER_SELF_SPECS "" #endif -/* Adding -fopenmp should imply pthreads. This is particularly important - for targets that use different start files and suchlike. */ -#ifndef GOMP_SELF_SPECS -#define GOMP_SELF_SPECS "%{fopenmp: -pthread}" -#endif - -static const char *const driver_self_specs[] = { - DRIVER_SELF_SPECS, GOMP_SELF_SPECS -}; +static const char *const driver_self_specs[] = { DRIVER_SELF_SPECS }; #ifndef OPTION_DEFAULT_SPECS #define OPTION_DEFAULT_SPECS { "", "" } @@ -902,10 +864,6 @@ struct compiler const char *cpp_spec; /* If non-NULL, substitute this spec for `%C', rather than the usual cpp_spec. */ - const int combinable; /* If nonzero, compiler can deal with - multiple source files at once (IMA). */ - const int needs_preprocessing; /* If nonzero, source files need to - be run through a preprocessor. */ }; /* Pointer to a vector of `struct compiler' that gives the spec for @@ -931,25 +889,19 @@ static const struct compiler default_compilers[] = were not present when we built the driver, we will hit these copies and be given a more meaningful error than "file not used since linking is not done". */ - {".m", "#Objective-C", 0, 0, 0}, {".mi", "#Objective-C", 0, 0, 0}, - {".mm", "#Objective-C++", 0, 0, 0}, {".M", "#Objective-C++", 0, 0, 0}, - {".mii", "#Objective-C++", 0, 0, 0}, - {".cc", "#C++", 0, 0, 0}, {".cxx", "#C++", 0, 0, 0}, - {".cpp", "#C++", 0, 0, 0}, {".cp", "#C++", 0, 0, 0}, - {".c++", "#C++", 0, 0, 0}, {".C", "#C++", 0, 0, 0}, - {".CPP", "#C++", 0, 0, 0}, {".ii", "#C++", 0, 0, 0}, - {".ads", "#Ada", 0, 0, 0}, {".adb", "#Ada", 0, 0, 0}, - {".f", "#Fortran", 0, 0, 0}, {".for", "#Fortran", 0, 0, 0}, - {".fpp", "#Fortran", 0, 0, 0}, {".F", "#Fortran", 0, 0, 0}, - {".FOR", "#Fortran", 0, 0, 0}, {".FPP", "#Fortran", 0, 0, 0}, - {".f90", "#Fortran", 0, 0, 0}, {".f95", "#Fortran", 0, 0, 0}, - {".F90", "#Fortran", 0, 0, 0}, {".F95", "#Fortran", 0, 0, 0}, - {".r", "#Ratfor", 0, 0, 0}, - {".p", "#Pascal", 0, 0, 0}, {".pas", "#Pascal", 0, 0, 0}, - {".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0}, - {".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0}, + {".m", "#Objective-C", 0}, {".mi", "#Objective-C", 0}, + {".cc", "#C++", 0}, {".cxx", "#C++", 0}, {".cpp", "#C++", 0}, + {".cp", "#C++", 0}, {".c++", "#C++", 0}, {".C", "#C++", 0}, + {".CPP", "#C++", 0}, {".ii", "#C++", 0}, + {".ads", "#Ada", 0}, {".adb", "#Ada", 0}, + {".f", "#Fortran", 0}, {".for", "#Fortran", 0}, {".fpp", "#Fortran", 0}, + {".F", "#Fortran", 0}, {".FOR", "#Fortran", 0}, {".FPP", "#Fortran", 0}, + {".r", "#Ratfor", 0}, + {".p", "#Pascal", 0}, {".pas", "#Pascal", 0}, + {".java", "#Java", 0}, {".class", "#Java", 0}, + {".zip", "#Java", 0}, {".jar", "#Java", 0}, /* Next come the entries for C. */ - {".c", "@c", 0, 1, 1}, + {".c", "@c", 0}, {"@c", /* cc1 has an integrated ISO C preprocessor. We should invoke the external preprocessor if -save-temps is given. */ @@ -957,24 +909,17 @@ static const struct compiler default_compilers[] = %{!E:%{!M:%{!MM:\ %{traditional|ftraditional:\ %eGNU C no longer supports -traditional without -E}\ - %{!combine:\ %{save-temps|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \ %(cpp_options) -o %{save-temps:%b.i} %{!save-temps:%g.i} \n\ cc1 -fpreprocessed %{save-temps:%b.i} %{!save-temps:%g.i} \ %(cc1_options)}\ %{!save-temps:%{!traditional-cpp:%{!no-integrated-cpp:\ cc1 %(cpp_unique_options) %(cc1_options)}}}\ - %{!fsyntax-only:%(invoke_as)}} \ - %{combine:\ - %{save-temps|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \ - %(cpp_options) -o %{save-temps:%b.i} %{!save-temps:%g.i}}\ - %{!save-temps:%{!traditional-cpp:%{!no-integrated-cpp:\ - cc1 %(cpp_unique_options) %(cc1_options)}}\ - %{!fsyntax-only:%(invoke_as)}}}}}}", 0, 1, 1}, + %{!fsyntax-only:%(invoke_as)}}}}", 0}, {"-", "%{!E:%e-E or -x required when input is from standard input}\ - %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0, 0, 0}, - {".h", "@c-header", 0, 0, 0}, + %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0}, + {".h", "@c-header", 0}, {"@c-header", /* cc1 has an integrated ISO C preprocessor. We should invoke the external preprocessor if -save-temps is given. */ @@ -989,14 +934,14 @@ static const struct compiler default_compilers[] = %{!save-temps:%{!traditional-cpp:%{!no-integrated-cpp:\ cc1 %(cpp_unique_options) %(cc1_options)\ -o %g.s %{!o*:--output-pch=%i.gch}\ - %W{o*:--output-pch=%*}%V}}}}}}", 0, 0, 0}, - {".i", "@cpp-output", 0, 1, 0}, + %W{o*:--output-pch=%*}%V}}}}}}", 0}, + {".i", "@cpp-output", 0}, {"@cpp-output", - "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0, 1, 0}, - {".s", "@assembler", 0, 1, 0}, + "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0}, + {".s", "@assembler", 0}, {"@assembler", - "%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0, 1, 0}, - {".S", "@assembler-with-cpp", 0, 1, 0}, + "%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0}, + {".S", "@assembler-with-cpp", 0}, {"@assembler-with-cpp", #ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT "%(trad_capable_cpp) -lang-asm %(cpp_options)\ @@ -1009,11 +954,11 @@ static const struct compiler default_compilers[] = %{!M:%{!MM:%{!E:%{!S:-o %|.s |\n\ as %(asm_debug) %(asm_options) %m.s %A }}}}" #endif - , 0, 1, 0}, + , 0}, #include "specs.h" /* Mark end of table. */ - {0, 0, 0, 0, 0} + {0, 0, 0} }; /* Number of elements in default_compilers, not counting the terminator. */ @@ -1067,7 +1012,6 @@ static const struct option_map option_map[] = {"--classpath", "-fclasspath=", "aj"}, {"--bootclasspath", "-fbootclasspath=", "aj"}, {"--CLASSPATH", "-fclasspath=", "aj"}, - {"--combine", "-combine", 0}, {"--comments", "-C", 0}, {"--comments-in-macros", "-CC", 0}, {"--compile", "-c", 0}, @@ -1076,14 +1020,11 @@ static const struct option_map option_map[] = {"--dependencies", "-M", 0}, {"--dump", "-d", "a"}, {"--dumpbase", "-dumpbase", "a"}, - {"--encoding", "-fencoding=", "aj"}, {"--entry", "-e", 0}, {"--extra-warnings", "-W", 0}, - {"--extdirs", "-fextdirs=", "aj"}, {"--for-assembler", "-Wa", "a"}, {"--for-linker", "-Xlinker", "a"}, {"--force-link", "-u", "a"}, - {"--coverage", "-coverage", 0}, {"--imacros", "-imacros", "a"}, {"--include", "-include", "a"}, {"--include-barrier", "-I-", 0}, @@ -1107,7 +1048,6 @@ static const struct option_map option_map[] = {"--output", "-o", "a"}, {"--output-class-directory", "-foutput-class-dir=", "ja"}, {"--param", "--param", "a"}, - {"--pass-exit-codes", "-pass-exit-codes", 0}, {"--pedantic", "-pedantic", 0}, {"--pedantic-errors", "-pedantic-errors", 0}, {"--pie", "-pie", 0}, @@ -1133,7 +1073,6 @@ static const struct option_map option_map[] = {"--static", "-static", 0}, {"--std", "-std=", "aj"}, {"--symbolic", "-symbolic", 0}, - {"--sysroot", "--sysroot=", "aj"}, {"--time", "-time", 0}, {"--trace-includes", "-H", 0}, {"--traditional", "-traditional", 0}, @@ -1281,7 +1220,7 @@ translate_options (int *argcp, const char *const **argvp) else if (strchr (arginfo, '*') != 0) { - error ("incomplete '%s' option", option_map[j].name); + error ("incomplete `%s' option", option_map[j].name); break; } @@ -1292,7 +1231,7 @@ translate_options (int *argcp, const char *const **argvp) { if (i + 1 == argc) { - error ("missing argument to '%s' option", + error ("missing argument to `%s' option", option_map[j].name); break; } @@ -1305,7 +1244,7 @@ translate_options (int *argcp, const char *const **argvp) else if (strchr (arginfo, 'o') == 0) { if (arg != 0) - error ("extraneous argument to '%s' option", + error ("extraneous argument to `%s' option", option_map[j].name); arg = 0; } @@ -1404,6 +1343,7 @@ struct prefix_list struct prefix_list *next; /* Next in linked list. */ int require_machine_suffix; /* Don't use without machine_suffix. */ /* 2 means try both machine_suffix and just_machine_suffix. */ + int *used_flag_ptr; /* 1 if a file was found with this prefix. */ int priority; /* Sort key - priority within list. */ int os_multilib; /* 1 if OS multilib scheme should be used, 0 for GCC multilib scheme. */ @@ -1448,13 +1388,6 @@ static const char *gcc_libexec_prefix; /* Default prefixes to attach to command names. */ -#ifndef STANDARD_STARTFILE_PREFIX_1 -#define STANDARD_STARTFILE_PREFIX_1 "/lib/" -#endif -#ifndef STANDARD_STARTFILE_PREFIX_2 -#define STANDARD_STARTFILE_PREFIX_2 "/usr/lib/" -#endif - #ifdef CROSS_COMPILE /* Don't use these prefixes for a cross compiler. */ #undef MD_EXEC_PREFIX #undef MD_STARTFILE_PREFIX @@ -1480,15 +1413,15 @@ static const char *md_exec_prefix = MD_EXEC_PREFIX; static const char *md_startfile_prefix = MD_STARTFILE_PREFIX; static const char *md_startfile_prefix_1 = MD_STARTFILE_PREFIX_1; static const char *const standard_startfile_prefix = STANDARD_STARTFILE_PREFIX; -static const char *const standard_startfile_prefix_1 - = STANDARD_STARTFILE_PREFIX_1; -static const char *const standard_startfile_prefix_2 - = STANDARD_STARTFILE_PREFIX_2; +static const char *const standard_startfile_prefix_1 = "/lib/"; +static const char *const standard_startfile_prefix_2 = "/usr/lib/"; static const char *const tooldir_base_prefix = TOOLDIR_BASE_PREFIX; static const char *tooldir_prefix; +#ifndef FREEBSD_NATIVE static const char *const standard_bindir_prefix = STANDARD_BINDIR_PREFIX; +#endif /* not FREEBSD_NATIVE */ static const char *standard_libexec_prefix = STANDARD_LIBEXEC_PREFIX; @@ -1541,13 +1474,9 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("cc1_options", &cc1_options), INIT_STATIC_SPEC ("cc1plus", &cc1plus_spec), INIT_STATIC_SPEC ("link_gcc_c_sequence", &link_gcc_c_sequence_spec), - INIT_STATIC_SPEC ("link_ssp", &link_ssp_spec), INIT_STATIC_SPEC ("endfile", &endfile_spec), INIT_STATIC_SPEC ("link", &link_spec), INIT_STATIC_SPEC ("lib", &lib_spec), - INIT_STATIC_SPEC ("mfwrap", &mfwrap_spec), - INIT_STATIC_SPEC ("mflib", &mflib_spec), - INIT_STATIC_SPEC ("link_gomp", &link_gomp_spec), INIT_STATIC_SPEC ("libgcc", &libgcc_spec), INIT_STATIC_SPEC ("startfile", &startfile_spec), INIT_STATIC_SPEC ("switches_need_spaces", &switches_need_spaces), @@ -1565,7 +1494,6 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("md_startfile_prefix", &md_startfile_prefix), INIT_STATIC_SPEC ("md_startfile_prefix_1", &md_startfile_prefix_1), INIT_STATIC_SPEC ("startfile_prefix_spec", &startfile_prefix_spec), - INIT_STATIC_SPEC ("sysroot_spec", &sysroot_spec), INIT_STATIC_SPEC ("sysroot_suffix_spec", &sysroot_suffix_spec), INIT_STATIC_SPEC ("sysroot_hdrs_suffix_spec", &sysroot_hdrs_suffix_spec), }; @@ -1593,12 +1521,6 @@ static const struct spec_function static_spec_functions[] = { { "if-exists", if_exists_spec_function }, { "if-exists-else", if_exists_else_spec_function }, - { "replace-outfile", replace_outfile_spec_function }, - { "version-compare", version_compare_spec_function }, - { "include", include_spec_function }, -#ifdef EXTRA_SPEC_FUNCTIONS - EXTRA_SPEC_FUNCTIONS -#endif { 0, 0 } }; @@ -1607,42 +1529,32 @@ static int processing_spec_function; /* Add appropriate libgcc specs to OBSTACK, taking into account various permutations of -shared-libgcc, -shared, and such. */ -#if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC) - -#ifndef USE_LD_AS_NEEDED -#define USE_LD_AS_NEEDED 0 -#endif - +#ifdef ENABLE_SHARED_LIBGCC static void init_gcc_specs (struct obstack *obstack, const char *shared_name, const char *static_name, const char *eh_name) { char *buf; - buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name, "}" - "%{!static:%{!static-libgcc:" -#if USE_LD_AS_NEEDED - "%{!shared-libgcc:", - static_name, " --as-needed ", shared_name, " --no-as-needed" - "}" - "%{shared-libgcc:", - shared_name, "%{!shared: ", static_name, "}" - "}" + buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name, + "}%{!static:%{!static-libgcc:", +#ifdef HAVE_LD_AS_NEEDED + "%{!shared-libgcc:", static_name, + " --as-needed ", shared_name, " --no-as-needed}" + "%{shared-libgcc:", shared_name, "%{!shared: ", static_name, + "}", #else - "%{!shared:" - "%{!shared-libgcc:", static_name, " ", eh_name, "}" - "%{shared-libgcc:", shared_name, " ", static_name, "}" - "}" + "%{!shared:%{!shared-libgcc:", static_name, " ", + eh_name, "}%{shared-libgcc:", shared_name, " ", + static_name, "}}%{shared:", #ifdef LINK_EH_SPEC - "%{shared:" - "%{shared-libgcc:", shared_name, "}" - "%{!shared-libgcc:", static_name, "}" - "}" + "%{shared-libgcc:", shared_name, + "}%{!shared-libgcc:", static_name, "}", #else - "%{shared:", shared_name, "}" + shared_name, #endif #endif - "}}", NULL); + "}}}", NULL); obstack_grow (obstack, buf, strlen (buf)); free (buf); @@ -1691,7 +1603,7 @@ init_spec (void) next = sl; } -#if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC) +#ifdef ENABLE_SHARED_LIBGCC /* ??? If neither -shared-libgcc nor --static-libgcc was seen, then we should be making an educated guess. Some proposed heuristics for ELF include: @@ -1730,7 +1642,11 @@ init_spec (void) if (in_sep && *p == '-' && strncmp (p, "-lgcc", 5) == 0) { init_gcc_specs (&obstack, +#ifdef NO_SHARED_LIBGCC_MULTILIB "-lgcc_s" +#else + "-lgcc_s%M" +#endif #ifdef USE_LIBUNWIND_EXCEPTIONS " -lunwind" #endif @@ -1754,7 +1670,12 @@ init_spec (void) /* Ug. We don't know shared library extensions. Hope that systems that use this form don't do shared libraries. */ init_gcc_specs (&obstack, - "-lgcc_s", +#ifdef NO_SHARED_LIBGCC_MULTILIB + "-lgcc_s" +#else + "-lgcc_s%M" +#endif + , "libgcc.a%s", "libgcc_eh.a%s" #ifdef USE_LIBUNWIND_EXCEPTIONS @@ -1773,7 +1694,7 @@ init_spec (void) } obstack_1grow (&obstack, '\0'); - libgcc_spec = XOBFINISH (&obstack, const char *); + libgcc_spec = obstack_finish (&obstack); } #endif #ifdef USE_AS_TRADITIONAL_FORMAT @@ -1782,14 +1703,14 @@ init_spec (void) static const char tf[] = "--traditional-format "; obstack_grow (&obstack, tf, sizeof(tf) - 1); obstack_grow0 (&obstack, asm_spec, strlen (asm_spec)); - asm_spec = XOBFINISH (&obstack, const char *); + asm_spec = obstack_finish (&obstack); } #endif #ifdef LINK_EH_SPEC /* Prepend LINK_EH_SPEC to whatever link_spec we had before. */ obstack_grow (&obstack, LINK_EH_SPEC, sizeof(LINK_EH_SPEC) - 1); obstack_grow0 (&obstack, link_spec, strlen (link_spec)); - link_spec = XOBFINISH (&obstack, const char *); + link_spec = obstack_finish (&obstack); #endif specs = sl; @@ -1828,7 +1749,7 @@ set_spec (const char *name, const char *spec) if (!sl) { /* Not found - make it. */ - sl = XNEW (struct spec_list); + sl = xmalloc (sizeof (struct spec_list)); sl->name = xstrdup (name); sl->name_len = name_len; sl->ptr_spec = &sl->ptr; @@ -1869,17 +1790,6 @@ static int argbuf_length; static int argbuf_index; -/* Position in the argbuf array containing the name of the output file - (the value associated with the "-o" flag). */ - -static int have_o_argbuf_index = 0; - -/* Were the options -c or -S passed. */ -static int have_c = 0; - -/* Was the option -o passed. */ -static int have_o = 0; - /* This is the list of suffixes and codes (%g/%u/%U/%j) and the associated temp file. If the HOST_BIT_BUCKET is used for %j, no entry is made for it here. */ @@ -1911,7 +1821,7 @@ static void alloc_args (void) { argbuf_length = 10; - argbuf = XNEWVEC (const char *, argbuf_length); + argbuf = xmalloc (argbuf_length * sizeof (const char *)); } /* Clear out the vector of arguments (after a command is executed). */ @@ -1938,8 +1848,6 @@ store_arg (const char *arg, int delete_always, int delete_failure) argbuf[argbuf_index++] = arg; argbuf[argbuf_index] = 0; - if (strcmp (arg, "-o") == 0) - have_o_argbuf_index = argbuf_index; if (delete_always || delete_failure) record_temp_file (arg, delete_always, delete_failure); } @@ -1970,14 +1878,14 @@ load_specs (const char *filename) pfatal_with_name (filename); /* Read contents of file into BUFFER. */ - buffer = XNEWVEC (char, statbuf.st_size + 1); + buffer = xmalloc ((unsigned) statbuf.st_size + 1); readlen = read (desc, buffer, (unsigned) statbuf.st_size); if (readlen < 0) pfatal_with_name (filename); buffer[readlen] = 0; close (desc); - specs = XNEWVEC (char, readlen + 1); + specs = xmalloc (readlen + 1); specs_p = specs; for (buffer_p = buffer; buffer_p && *buffer_p; buffer_p++) { @@ -2060,7 +1968,7 @@ read_specs (const char *filename, int main_p) (long) (p1 - buffer + 1)); p[-2] = '\0'; - new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true); + new_filename = find_a_file (&startfile_prefixes, p1, R_OK, 0); read_specs (new_filename ? new_filename : p1, FALSE); continue; } @@ -2079,7 +1987,7 @@ read_specs (const char *filename, int main_p) (long) (p1 - buffer + 1)); p[-2] = '\0'; - new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true); + new_filename = find_a_file (&startfile_prefixes, p1, R_OK, 0); if (new_filename) read_specs (new_filename, FALSE); else if (verbose_flag) @@ -2293,7 +2201,7 @@ record_temp_file (const char *filename, int always_delete, int fail_delete) if (! strcmp (name, temp->name)) goto already1; - temp = XNEW (struct temp_file); + temp = xmalloc (sizeof (struct temp_file)); temp->next = always_delete_queue; temp->name = name; always_delete_queue = temp; @@ -2308,7 +2216,7 @@ record_temp_file (const char *filename, int always_delete, int fail_delete) if (! strcmp (name, temp->name)) goto already2; - temp = XNEW (struct temp_file); + temp = xmalloc (sizeof (struct temp_file)); temp->next = failure_delete_queue; temp->name = name; failure_delete_queue = temp; @@ -2319,17 +2227,6 @@ record_temp_file (const char *filename, int always_delete, int fail_delete) /* Delete all the temporary files whose names we previously recorded. */ -#ifndef DELETE_IF_ORDINARY -#define DELETE_IF_ORDINARY(NAME,ST,VERBOSE_FLAG) \ -do \ - { \ - if (stat (NAME, &ST) >= 0 && S_ISREG (ST.st_mode)) \ - if (unlink (NAME) < 0) \ - if (VERBOSE_FLAG) \ - perror_with_name (NAME); \ - } while (0) -#endif - static void delete_if_ordinary (const char *name) { @@ -2346,7 +2243,10 @@ delete_if_ordinary (const char *name) if (i == 'y' || i == 'Y') #endif /* DEBUG */ - DELETE_IF_ORDINARY (name, st, verbose_flag); + if (stat (name, &st) >= 0 && S_ISREG (st.st_mode)) + if (unlink (name) < 0) + if (verbose_flag) + perror_with_name (name); } static void @@ -2376,226 +2276,76 @@ clear_failure_queue (void) failure_delete_queue = 0; } -/* Call CALLBACK for each path in PATHS, breaking out early if CALLBACK - returns non-NULL. - If DO_MULTI is true iterate over the paths twice, first with multilib - suffix then without, otherwise iterate over the paths once without - adding a multilib suffix. When DO_MULTI is true, some attempt is made - to avoid visiting the same path twice, but we could do better. For - instance, /usr/lib/../lib is considered different from /usr/lib. - At least EXTRA_SPACE chars past the end of the path passed to - CALLBACK are available for use by the callback. - CALLBACK_INFO allows extra parameters to be passed to CALLBACK. - - Returns the value returned by CALLBACK. */ - -static void * -for_each_path (const struct path_prefix *paths, - bool do_multi, - size_t extra_space, - void *(*callback) (char *, void *), - void *callback_info) +/* Build a list of search directories from PATHS. + PREFIX is a string to prepend to the list. + If CHECK_DIR_P is nonzero we ensure the directory exists. + This is used mostly by putenv_from_prefixes so we use `collect_obstack'. + It is also used by the --print-search-dirs flag. */ + +static char * +build_search_list (struct path_prefix *paths, const char *prefix, + int check_dir_p) { - struct prefix_list *pl; - const char *multi_dir = NULL; - const char *multi_os_dir = NULL; - const char *multi_suffix; - const char *just_multi_suffix; - char *path = NULL; - void *ret = NULL; - bool skip_multi_dir = false; - bool skip_multi_os_dir = false; - - multi_suffix = machine_suffix; - just_multi_suffix = just_machine_suffix; - if (do_multi && multilib_dir && strcmp (multilib_dir, ".") != 0) - { - multi_dir = concat (multilib_dir, dir_separator_str, NULL); - multi_suffix = concat (multi_suffix, multi_dir, NULL); - just_multi_suffix = concat (just_multi_suffix, multi_dir, NULL); - } - if (do_multi && multilib_os_dir && strcmp (multilib_os_dir, ".") != 0) - multi_os_dir = concat (multilib_os_dir, dir_separator_str, NULL); + int suffix_len = (machine_suffix) ? strlen (machine_suffix) : 0; + int just_suffix_len + = (just_machine_suffix) ? strlen (just_machine_suffix) : 0; + int first_time = TRUE; + struct prefix_list *pprefix; - while (1) + obstack_grow (&collect_obstack, prefix, strlen (prefix)); + obstack_1grow (&collect_obstack, '='); + + for (pprefix = paths->plist; pprefix != 0; pprefix = pprefix->next) { - size_t multi_dir_len = 0; - size_t multi_os_dir_len = 0; - size_t suffix_len; - size_t just_suffix_len; - size_t len; - - if (multi_dir) - multi_dir_len = strlen (multi_dir); - if (multi_os_dir) - multi_os_dir_len = strlen (multi_os_dir); - suffix_len = strlen (multi_suffix); - just_suffix_len = strlen (just_multi_suffix); - - if (path == NULL) - { - len = paths->max_len + extra_space + 1; - if (suffix_len > multi_os_dir_len) - len += suffix_len; - else - len += multi_os_dir_len; - path = XNEWVEC (char, len); - } + int len = strlen (pprefix->prefix); - for (pl = paths->plist; pl != 0; pl = pl->next) + if (machine_suffix + && (! check_dir_p + || is_directory (pprefix->prefix, machine_suffix, 0))) { - len = strlen (pl->prefix); - memcpy (path, pl->prefix, len); - - /* Look first in MACHINE/VERSION subdirectory. */ - if (!skip_multi_dir) - { - memcpy (path + len, multi_suffix, suffix_len + 1); - ret = callback (path, callback_info); - if (ret) - break; - } - - /* Some paths are tried with just the machine (ie. target) - subdir. This is used for finding as, ld, etc. */ - if (!skip_multi_dir - && pl->require_machine_suffix == 2) - { - memcpy (path + len, just_multi_suffix, just_suffix_len + 1); - ret = callback (path, callback_info); - if (ret) - break; - } - - /* Now try the base path. */ - if (!pl->require_machine_suffix - && !(pl->os_multilib ? skip_multi_os_dir : skip_multi_dir)) - { - const char *this_multi; - size_t this_multi_len; - - if (pl->os_multilib) - { - this_multi = multi_os_dir; - this_multi_len = multi_os_dir_len; - } - else - { - this_multi = multi_dir; - this_multi_len = multi_dir_len; - } - - if (this_multi_len) - memcpy (path + len, this_multi, this_multi_len + 1); - else - path[len] = '\0'; + if (!first_time) + obstack_1grow (&collect_obstack, PATH_SEPARATOR); - ret = callback (path, callback_info); - if (ret) - break; - } + first_time = FALSE; + obstack_grow (&collect_obstack, pprefix->prefix, len); + obstack_grow (&collect_obstack, machine_suffix, suffix_len); } - if (pl) - break; - if (multi_dir == NULL && multi_os_dir == NULL) - break; - - /* Run through the paths again, this time without multilibs. - Don't repeat any we have already seen. */ - if (multi_dir) + if (just_machine_suffix + && pprefix->require_machine_suffix == 2 + && (! check_dir_p + || is_directory (pprefix->prefix, just_machine_suffix, 0))) { - free ((char *) multi_dir); - multi_dir = NULL; - free ((char *) multi_suffix); - multi_suffix = machine_suffix; - free ((char *) just_multi_suffix); - just_multi_suffix = just_machine_suffix; + if (! first_time) + obstack_1grow (&collect_obstack, PATH_SEPARATOR); + + first_time = FALSE; + obstack_grow (&collect_obstack, pprefix->prefix, len); + obstack_grow (&collect_obstack, just_machine_suffix, + just_suffix_len); } - else - skip_multi_dir = true; - if (multi_os_dir) + + if (! pprefix->require_machine_suffix) { - free ((char *) multi_os_dir); - multi_os_dir = NULL; - } - else - skip_multi_os_dir = true; - } + if (! first_time) + obstack_1grow (&collect_obstack, PATH_SEPARATOR); - if (multi_dir) - { - free ((char *) multi_dir); - free ((char *) multi_suffix); - free ((char *) just_multi_suffix); + first_time = FALSE; + obstack_grow (&collect_obstack, pprefix->prefix, len); + } } - if (multi_os_dir) - free ((char *) multi_os_dir); - if (ret != path) - free (path); - return ret; -} - -/* Callback for build_search_list. Adds path to obstack being built. */ - -struct add_to_obstack_info { - struct obstack *ob; - bool check_dir; - bool first_time; -}; - -static void * -add_to_obstack (char *path, void *data) -{ - struct add_to_obstack_info *info = data; - - if (info->check_dir && !is_directory (path, false)) - return NULL; - - if (!info->first_time) - obstack_1grow (info->ob, PATH_SEPARATOR); - - obstack_grow (info->ob, path, strlen (path)); - - info->first_time = false; - return NULL; -} - -/* Build a list of search directories from PATHS. - PREFIX is a string to prepend to the list. - If CHECK_DIR_P is true we ensure the directory exists. - If DO_MULTI is true, multilib paths are output first, then - non-multilib paths. - This is used mostly by putenv_from_prefixes so we use `collect_obstack'. - It is also used by the --print-search-dirs flag. */ - -static char * -build_search_list (const struct path_prefix *paths, const char *prefix, - bool check_dir, bool do_multi) -{ - struct add_to_obstack_info info; - - info.ob = &collect_obstack; - info.check_dir = check_dir; - info.first_time = true; - - obstack_grow (&collect_obstack, prefix, strlen (prefix)); - obstack_1grow (&collect_obstack, '='); - - for_each_path (paths, do_multi, 0, add_to_obstack, &info); obstack_1grow (&collect_obstack, '\0'); - return XOBFINISH (&collect_obstack, char *); + return obstack_finish (&collect_obstack); } /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect. */ static void -putenv_from_prefixes (const struct path_prefix *paths, const char *env_var, - bool do_multi) +putenv_from_prefixes (struct path_prefix *paths, const char *env_var) { - putenv (build_search_list (paths, env_var, true, do_multi)); + putenv (build_search_list (paths, env_var, 1)); } /* Check whether NAME can be accessed in MODE. This is like access, @@ -2616,53 +2366,20 @@ access_check (const char *name, int mode) return access (name, mode); } -/* Callback for find_a_file. Appends the file name to the directory - path. If the resulting file exists in the right mode, return the - full pathname to the file. */ - -struct file_at_path_info { - const char *name; - const char *suffix; - int name_len; - int suffix_len; - int mode; -}; - -static void * -file_at_path (char *path, void *data) -{ - struct file_at_path_info *info = data; - size_t len = strlen (path); - - memcpy (path + len, info->name, info->name_len); - len += info->name_len; - - /* Some systems have a suffix for executable files. - So try appending that first. */ - if (info->suffix_len) - { - memcpy (path + len, info->suffix, info->suffix_len + 1); - if (access_check (path, info->mode) == 0) - return path; - } - - path[len] = '\0'; - if (access_check (path, info->mode) == 0) - return path; - - return NULL; -} - /* Search for NAME using the prefix list PREFIXES. MODE is passed to - access to check permissions. If DO_MULTI is true, search multilib - paths then non-multilib paths, otherwise do not search multilib paths. + access to check permissions. Return 0 if not found, otherwise return its name, allocated with malloc. */ static char * -find_a_file (const struct path_prefix *pprefix, const char *name, int mode, - bool do_multi) +find_a_file (struct path_prefix *pprefix, const char *name, int mode, + int multilib) { - struct file_at_path_info info; + char *temp; + const char *const file_suffix = + ((mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : ""); + struct prefix_list *pl; + int len = pprefix->max_len + strlen (name) + strlen (file_suffix) + 1; + const char *multilib_name, *multilib_os_name; #ifdef DEFAULT_ASSEMBLER if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0) @@ -2674,24 +2391,136 @@ find_a_file (const struct path_prefix *pprefix, const char *name, int mode, return xstrdup (DEFAULT_LINKER); #endif + if (machine_suffix) + len += strlen (machine_suffix); + + multilib_name = name; + multilib_os_name = name; + if (multilib && multilib_os_dir) + { + int len1 = multilib_dir ? strlen (multilib_dir) + 1 : 0; + int len2 = strlen (multilib_os_dir) + 1; + + len += len1 > len2 ? len1 : len2; + if (multilib_dir) + multilib_name = ACONCAT ((multilib_dir, dir_separator_str, name, + NULL)); + if (strcmp (multilib_os_dir, ".") != 0) + multilib_os_name = ACONCAT ((multilib_os_dir, dir_separator_str, name, + NULL)); + } + + temp = xmalloc (len); + /* Determine the filename to execute (special case for absolute paths). */ if (IS_ABSOLUTE_PATH (name)) { if (access (name, mode) == 0) - return xstrdup (name); - - return NULL; + { + strcpy (temp, name); + return temp; + } } + else + for (pl = pprefix->plist; pl; pl = pl->next) + { + const char *this_name + = pl->os_multilib ? multilib_os_name : multilib_name; + + if (machine_suffix) + { + /* Some systems have a suffix for executable files. + So try appending that first. */ + if (file_suffix[0] != 0) + { + strcpy (temp, pl->prefix); + strcat (temp, machine_suffix); + strcat (temp, multilib_name); + strcat (temp, file_suffix); + if (access_check (temp, mode) == 0) + { + if (pl->used_flag_ptr != 0) + *pl->used_flag_ptr = 1; + return temp; + } + } + + /* Now try just the multilib_name. */ + strcpy (temp, pl->prefix); + strcat (temp, machine_suffix); + strcat (temp, multilib_name); + if (access_check (temp, mode) == 0) + { + if (pl->used_flag_ptr != 0) + *pl->used_flag_ptr = 1; + return temp; + } + } + + /* Certain prefixes are tried with just the machine type, + not the version. This is used for finding as, ld, etc. */ + if (just_machine_suffix && pl->require_machine_suffix == 2) + { + /* Some systems have a suffix for executable files. + So try appending that first. */ + if (file_suffix[0] != 0) + { + strcpy (temp, pl->prefix); + strcat (temp, just_machine_suffix); + strcat (temp, multilib_name); + strcat (temp, file_suffix); + if (access_check (temp, mode) == 0) + { + if (pl->used_flag_ptr != 0) + *pl->used_flag_ptr = 1; + return temp; + } + } + + strcpy (temp, pl->prefix); + strcat (temp, just_machine_suffix); + strcat (temp, multilib_name); + if (access_check (temp, mode) == 0) + { + if (pl->used_flag_ptr != 0) + *pl->used_flag_ptr = 1; + return temp; + } + } + + /* Certain prefixes can't be used without the machine suffix + when the machine or version is explicitly specified. */ + if (! pl->require_machine_suffix) + { + /* Some systems have a suffix for executable files. + So try appending that first. */ + if (file_suffix[0] != 0) + { + strcpy (temp, pl->prefix); + strcat (temp, this_name); + strcat (temp, file_suffix); + if (access_check (temp, mode) == 0) + { + if (pl->used_flag_ptr != 0) + *pl->used_flag_ptr = 1; + return temp; + } + } - info.name = name; - info.suffix = (mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : ""; - info.name_len = strlen (info.name); - info.suffix_len = strlen (info.suffix); - info.mode = mode; + strcpy (temp, pl->prefix); + strcat (temp, this_name); + if (access_check (temp, mode) == 0) + { + if (pl->used_flag_ptr != 0) + *pl->used_flag_ptr = 1; + return temp; + } + } + } - return for_each_path (pprefix, do_multi, info.name_len + info.suffix_len, - file_at_path, &info); + free (temp); + return 0; } /* Ranking of prefixes in the sort list. -B prefixes are put before @@ -2720,7 +2549,7 @@ enum path_prefix_priority static void add_prefix (struct path_prefix *pprefix, const char *prefix, const char *component, /* enum prefix_priority */ int priority, - int require_machine_suffix, int os_multilib) + int require_machine_suffix, int *warn, int os_multilib) { struct prefix_list *pl, **prev; int len; @@ -2737,11 +2566,14 @@ add_prefix (struct path_prefix *pprefix, const char *prefix, if (len > pprefix->max_len) pprefix->max_len = len; - pl = XNEW (struct prefix_list); + pl = xmalloc (sizeof (struct prefix_list)); pl->prefix = prefix; pl->require_machine_suffix = require_machine_suffix; + pl->used_flag_ptr = warn; pl->priority = priority; pl->os_multilib = os_multilib; + if (warn) + *warn = 0; /* Insert after PREV. */ pl->next = (*prev); @@ -2753,10 +2585,10 @@ static void add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix, const char *component, /* enum prefix_priority */ int priority, - int require_machine_suffix, int os_multilib) + int require_machine_suffix, int *warn, int os_multilib) { if (!IS_ABSOLUTE_PATH (prefix)) - fatal ("system path '%s' is not absolute", prefix); + abort (); if (target_system_root) { @@ -2770,7 +2602,7 @@ add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix, } add_prefix (pprefix, prefix, component, priority, - require_machine_suffix, os_multilib); + require_machine_suffix, warn, os_multilib); } /* Execute the command specified by the arguments on the current line of spec. @@ -2785,16 +2617,17 @@ execute (void) int i; int n_commands; /* # of command. */ char *string; - struct pex_obj *pex; struct command { const char *prog; /* program name. */ const char **argv; /* vector of args. */ + int pid; /* pid of process for this command. */ }; struct command *commands; /* each command buffer with above info. */ - gcc_assert (!processing_spec_function); + if (processing_spec_function) + abort (); /* Count # of piped commands. */ for (n_commands = 1, i = 0; i < argbuf_index; i++) @@ -2810,7 +2643,7 @@ execute (void) commands[0].prog = argbuf[0]; /* first command. */ commands[0].argv = &argbuf[0]; - string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false); + string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, 0); if (string) commands[0].argv[0] = string; @@ -2825,7 +2658,7 @@ execute (void) commands[n_commands].prog = argbuf[i + 1]; commands[n_commands].argv = &argbuf[i + 1]; string = find_a_file (&exec_prefixes, commands[n_commands].prog, - X_OK, false); + X_OK, 0); if (string) commands[n_commands].argv[0] = string; n_commands++; @@ -2922,32 +2755,24 @@ execute (void) /* Run each piped subprocess. */ - pex = pex_init (PEX_USE_PIPES | (report_times ? PEX_RECORD_TIMES : 0), - programname, temp_filename); - if (pex == NULL) - pfatal_with_name (_("pex_init failed")); - for (i = 0; i < n_commands; i++) { - const char *errmsg; - int err; + char *errmsg_fmt, *errmsg_arg; const char *string = commands[i].argv[0]; - errmsg = pex_run (pex, - ((i + 1 == n_commands ? PEX_LAST : 0) - | (string == commands[i].prog ? PEX_SEARCH : 0)), - string, (char * const *) commands[i].argv, - NULL, NULL, &err); - if (errmsg != NULL) - { - if (err == 0) - fatal (errmsg); - else - { - errno = err; - pfatal_with_name (errmsg); - } - } + /* For some bizarre reason, the second argument of execvp() is + char *const *, not const char *const *. */ + commands[i].pid = pexecute (string, (char *const *) commands[i].argv, + programname, temp_filename, + &errmsg_fmt, &errmsg_arg, + ((i == 0 ? PEXECUTE_FIRST : 0) + | (i + 1 == n_commands ? PEXECUTE_LAST : 0) + | (string == commands[i].prog + ? PEXECUTE_SEARCH : 0) + | (verbose_flag ? PEXECUTE_VERBOSE : 0))); + + if (commands[i].pid == -1) + pfatal_pexecute (errmsg_fmt, errmsg_arg); if (string != commands[i].prog) free ((void *) string); @@ -2955,77 +2780,89 @@ execute (void) execution_count++; - /* Wait for all the subprocesses to finish. */ + /* Wait for all the subprocesses to finish. + We don't care what order they finish in; + we know that N_COMMANDS waits will get them all. + Ignore subprocesses that we don't know about, + since they can be spawned by the process that exec'ed us. */ { - int *statuses; - struct pex_time *times = NULL; int ret_code = 0; +#ifdef HAVE_GETRUSAGE + struct timeval d; + double ut = 0.0, st = 0.0; +#endif - statuses = alloca (n_commands * sizeof (int)); - if (!pex_get_status (pex, n_commands, statuses)) - pfatal_with_name (_("failed to get exit status")); - - if (report_times) + for (i = 0; i < n_commands;) { - times = alloca (n_commands * sizeof (struct pex_time)); - if (!pex_get_times (pex, n_commands, times)) - pfatal_with_name (_("failed to get process times")); - } + int j; + int status; + int pid; - pex_free (pex); + pid = pwait (commands[i].pid, &status, 0); + if (pid < 0) + abort (); - for (i = 0; i < n_commands; ++i) - { - int status = statuses[i]; - - if (WIFSIGNALED (status)) +#ifdef HAVE_GETRUSAGE + if (report_times) { + /* getrusage returns the total resource usage of all children + up to now. Copy the previous values into prus, get the + current statistics, then take the difference. */ + + prus = rus; + getrusage (RUSAGE_CHILDREN, &rus); + d.tv_sec = rus.ru_utime.tv_sec - prus.ru_utime.tv_sec; + d.tv_usec = rus.ru_utime.tv_usec - prus.ru_utime.tv_usec; + ut = (double) d.tv_sec + (double) d.tv_usec / 1.0e6; + + d.tv_sec = rus.ru_stime.tv_sec - prus.ru_stime.tv_sec; + d.tv_usec = rus.ru_stime.tv_usec - prus.ru_stime.tv_usec; + st = (double) d.tv_sec + (double) d.tv_usec / 1.0e6; + } +#endif + + for (j = 0; j < n_commands; j++) + if (commands[j].pid == pid) + { + i++; + if (WIFSIGNALED (status)) + { #ifdef SIGPIPE - /* SIGPIPE is a special case. It happens in -pipe mode - when the compiler dies before the preprocessor is done, - or the assembler dies before the compiler is done. - There's generally been an error already, and this is - just fallout. So don't generate another error unless - we would otherwise have succeeded. */ - if (WTERMSIG (status) == SIGPIPE - && (signal_count || greatest_status >= MIN_FATAL_STATUS)) - { - signal_count++; - ret_code = -1; - } - else + /* SIGPIPE is a special case. It happens in -pipe mode + when the compiler dies before the preprocessor is + done, or the assembler dies before the compiler is + done. There's generally been an error already, and + this is just fallout. So don't generate another error + unless we would otherwise have succeeded. */ + if (WTERMSIG (status) == SIGPIPE + && (signal_count || greatest_status >= MIN_FATAL_STATUS)) + ; + else #endif - fatal_ice ("\ + fatal ("\ Internal error: %s (program %s)\n\ Please submit a full bug report.\n\ See %s for instructions.", - strsignal (WTERMSIG (status)), commands[i].prog, - bug_report_url); - } - else if (WIFEXITED (status) - && WEXITSTATUS (status) >= MIN_FATAL_STATUS) - { - if (WEXITSTATUS (status) > greatest_status) - greatest_status = WEXITSTATUS (status); - ret_code = -1; - } - - if (report_times) - { - struct pex_time *pt = ×[i]; - double ut, st; - - ut = ((double) pt->user_seconds - + (double) pt->user_microseconds / 1.0e6); - st = ((double) pt->system_seconds - + (double) pt->system_microseconds / 1.0e6); - - if (ut + st != 0) - notice ("# %s %.2f %.2f\n", commands[i].prog, ut, st); - } + strsignal (WTERMSIG (status)), commands[j].prog, + bug_report_url); + signal_count++; + ret_code = -1; + } + else if (WIFEXITED (status) + && WEXITSTATUS (status) >= MIN_FATAL_STATUS) + { + if (WEXITSTATUS (status) > greatest_status) + greatest_status = WEXITSTATUS (status); + ret_code = -1; + } +#ifdef HAVE_GETRUSAGE + if (report_times && ut + st != 0) + notice ("# %s %.2f %.2f\n", commands[j].prog, ut, st); +#endif + break; + } } - return ret_code; } } @@ -3062,20 +2899,10 @@ static struct switchstr *switches; static int n_switches; -/* Language is one of three things: - - 1) The name of a real programming language. - 2) NULL, indicating that no one has figured out - what it is yet. - 3) '*', indicating that the file should be passed - to the linker. */ struct infile { const char *name; const char *language; - struct compiler *incompiler; - bool compiled; - bool preprocessed; }; /* Also a vector of input files specified. */ @@ -3097,6 +2924,12 @@ static int added_libraries; /* And a vector of corresponding output files is made up later. */ const char **outfiles; + +/* Used to track if none of the -B paths are used. */ +static int warn_B; + +/* Gives value to pass as "warn" to add_prefix for standard prefixes. */ +static int *warn_std_ptr = 0; #if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX) @@ -3126,7 +2959,7 @@ convert_filename (const char *name, int do_exe ATTRIBUTE_UNUSED, { obstack_grow (&obstack, name, len - 2); obstack_grow0 (&obstack, TARGET_OBJECT_SUFFIX, strlen (TARGET_OBJECT_SUFFIX)); - name = XOBFINISH (&obstack, const char *); + name = obstack_finish (&obstack); } #endif @@ -3147,7 +2980,7 @@ convert_filename (const char *name, int do_exe ATTRIBUTE_UNUSED, obstack_grow (&obstack, name, len); obstack_grow0 (&obstack, TARGET_EXECUTABLE_SUFFIX, strlen (TARGET_EXECUTABLE_SUFFIX)); - name = XOBFINISH (&obstack, const char *); + name = obstack_finish (&obstack); #endif return name; @@ -3184,15 +3017,11 @@ display_help (void) fputs (_(" -Xassembler <arg> Pass <arg> on to the assembler\n"), stdout); fputs (_(" -Xpreprocessor <arg> Pass <arg> on to the preprocessor\n"), stdout); fputs (_(" -Xlinker <arg> Pass <arg> on to the linker\n"), stdout); - fputs (_(" -combine Pass multiple source files to compiler at once\n"), stdout); fputs (_(" -save-temps Do not delete intermediate files\n"), stdout); fputs (_(" -pipe Use pipes rather than intermediate files\n"), stdout); fputs (_(" -time Time the execution of each subprocess\n"), stdout); fputs (_(" -specs=<file> Override built-in specs with the contents of <file>\n"), stdout); fputs (_(" -std=<standard> Assume that the input sources are for <standard>\n"), stdout); - fputs (_("\ - --sysroot=<directory> Use <directory> as the root directory for headers\n\ - and libraries\n"), stdout); fputs (_(" -B <directory> Add <directory> to the compiler's search paths\n"), stdout); fputs (_(" -b <machine> Run gcc for target <machine>, if installed\n"), stdout); fputs (_(" -V <version> Run gcc version number <version>, if installed\n"), stdout); @@ -3225,7 +3054,7 @@ add_preprocessor_option (const char *option, int len) n_preprocessor_options++; if (! preprocessor_options) - preprocessor_options = XNEWVEC (char *, n_preprocessor_options); + preprocessor_options = xmalloc (n_preprocessor_options * sizeof (char *)); else preprocessor_options = xrealloc (preprocessor_options, n_preprocessor_options * sizeof (char *)); @@ -3240,7 +3069,7 @@ add_assembler_option (const char *option, int len) n_assembler_options++; if (! assembler_options) - assembler_options = XNEWVEC (char *, n_assembler_options); + assembler_options = xmalloc (n_assembler_options * sizeof (char *)); else assembler_options = xrealloc (assembler_options, n_assembler_options * sizeof (char *)); @@ -3254,7 +3083,7 @@ add_linker_option (const char *option, int len) n_linker_options++; if (! linker_options) - linker_options = XNEWVEC (char *, n_linker_options); + linker_options = xmalloc (n_linker_options * sizeof (char *)); else linker_options = xrealloc (linker_options, n_linker_options * sizeof (char *)); @@ -3273,10 +3102,12 @@ process_command (int argc, const char **argv) char *temp1; const char *spec_lang = 0; int last_language_n_infiles; + int have_c = 0; + int have_o = 0; int lang_n_infiles = 0; #ifdef MODIFY_TARGET_NAME int is_modify_target_name; - unsigned int j; + int j; #endif GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX"); @@ -3299,12 +3130,9 @@ process_command (int argc, const char **argv) } /* If there is a -V or -b option (or both), process it now, before - trying to interpret the rest of the command line. - Use heuristic that all configuration names must have at least - one dash '-'. This allows us to pass options starting with -b. */ + trying to interpret the rest of the command line. */ if (argc > 1 && argv[1][0] == '-' - && (argv[1][1] == 'V' || - ((argv[1][1] == 'b') && (NULL != strchr(argv[1] + 2,'-'))))) + && (argv[1][1] == 'V' || argv[1][1] == 'b')) { const char *new_version = DEFAULT_TARGET_VERSION; const char *new_machine = DEFAULT_TARGET_MACHINE; @@ -3314,8 +3142,7 @@ process_command (int argc, const char **argv) int baselen; while (argc > 1 && argv[1][0] == '-' - && (argv[1][1] == 'V' || - ((argv[1][1] == 'b') && ( NULL != strchr(argv[1] + 2,'-'))))) + && (argv[1][1] == 'V' || argv[1][1] == 'b')) { char opt = argv[1][1]; const char *arg; @@ -3332,7 +3159,7 @@ process_command (int argc, const char **argv) argv += 2; } else - fatal ("'-%c' option must have argument", opt); + fatal ("`-%c' option must have argument", opt); if (opt == 'V') new_version = arg; else @@ -3354,39 +3181,33 @@ process_command (int argc, const char **argv) new_argv[0] = new_argv0; execvp (new_argv0, new_argv); - fatal ("couldn't run '%s': %s", new_argv0, xstrerror (errno)); + fatal ("couldn't run `%s': %s", new_argv0, xstrerror (errno)); } /* Set up the default search paths. If there is no GCC_EXEC_PREFIX, see if we can create it from the pathname specified in argv[0]. */ gcc_libexec_prefix = standard_libexec_prefix; +#ifndef FREEBSD_NATIVE #ifndef VMS /* FIXME: make_relative_prefix doesn't yet work for VMS. */ if (!gcc_exec_prefix) { gcc_exec_prefix = make_relative_prefix (argv[0], standard_bindir_prefix, standard_exec_prefix); - gcc_libexec_prefix = make_relative_prefix (argv[0], + gcc_libexec_prefix = make_relative_prefix (argv[0], standard_bindir_prefix, standard_libexec_prefix); if (gcc_exec_prefix) putenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL)); } else - { - /* make_relative_prefix requires a program name, but - GCC_EXEC_PREFIX is typically a directory name with a trailing - / (which is ignored by make_relative_prefix), so append a - program name. */ - char *tmp_prefix = concat (gcc_exec_prefix, "gcc", NULL); - gcc_libexec_prefix = make_relative_prefix (tmp_prefix, - standard_exec_prefix, - standard_libexec_prefix); - free (tmp_prefix); - } + gcc_libexec_prefix = make_relative_prefix (gcc_exec_prefix, + standard_exec_prefix, + standard_libexec_prefix); #else #endif +#endif /* not FREEBSD_NATIVE */ if (gcc_exec_prefix) { @@ -3405,9 +3226,9 @@ process_command (int argc, const char **argv) set_std_prefix (gcc_exec_prefix, len); add_prefix (&exec_prefixes, gcc_libexec_prefix, "GCC", - PREFIX_PRIORITY_LAST, 0, 0); + PREFIX_PRIORITY_LAST, 0, NULL, 0); add_prefix (&startfile_prefixes, gcc_exec_prefix, "GCC", - PREFIX_PRIORITY_LAST, 0, 0); + PREFIX_PRIORITY_LAST, 0, NULL, 0); } /* COMPILER_PATH and LIBRARY_PATH have values @@ -3435,9 +3256,10 @@ process_command (int argc, const char **argv) else nstore[endp - startp] = 0; add_prefix (&exec_prefixes, nstore, 0, - PREFIX_PRIORITY_LAST, 0, 0); - add_prefix (&include_prefixes, nstore, 0, - PREFIX_PRIORITY_LAST, 0, 0); + PREFIX_PRIORITY_LAST, 0, NULL, 0); + add_prefix (&include_prefixes, + concat (nstore, "include", NULL), + 0, PREFIX_PRIORITY_LAST, 0, NULL, 0); if (*endp == 0) break; endp = startp = endp + 1; @@ -3469,7 +3291,7 @@ process_command (int argc, const char **argv) else nstore[endp - startp] = 0; add_prefix (&startfile_prefixes, nstore, NULL, - PREFIX_PRIORITY_LAST, 0, 1); + PREFIX_PRIORITY_LAST, 0, NULL, 1); if (*endp == 0) break; endp = startp = endp + 1; @@ -3502,7 +3324,7 @@ process_command (int argc, const char **argv) else nstore[endp - startp] = 0; add_prefix (&startfile_prefixes, nstore, NULL, - PREFIX_PRIORITY_LAST, 0, 1); + PREFIX_PRIORITY_LAST, 0, NULL, 1); if (*endp == 0) break; endp = startp = endp + 1; @@ -3512,6 +3334,44 @@ process_command (int argc, const char **argv) } } + /* Options specified as if they appeared on the command line. */ + temp = getenv ("GCC_OPTIONS"); + if ((temp) && (strlen (temp) > 0)) + { + int len; + int optc = 1; + int new_argc; + const char **new_argv; + char *envopts; + + while (isspace (*temp)) + temp++; + len = strlen (temp); + envopts = (char *) xmalloc (len + 1); + strcpy (envopts, temp); + + for (i = 0; i < (len - 1); i++) + if ((isspace (envopts[i])) && ! (isspace (envopts[i+1]))) + optc++; + + new_argv = (const char **) alloca ((optc + argc) * sizeof(char *)); + + for (i = 0, new_argc = 1; new_argc <= optc; new_argc++) + { + while (isspace (envopts[i])) + i++; + new_argv[new_argc] = envopts + i; + while (!isspace (envopts[i]) && (envopts[i] != '\0')) + i++; + envopts[i++] = '\0'; + } + for (i = 1; i < argc; i++) + new_argv[new_argc++] = argv[i]; + + argv = new_argv; + argc = new_argc; + } + /* Convert new-style -- options to old-style. */ translate_options (&argc, (const char *const **) &argv); @@ -3548,7 +3408,7 @@ process_command (int argc, const char **argv) { /* translate_options () has turned --version into -fversion. */ printf (_("%s (GCC) %s\n"), programname, version_string); - printf ("Copyright %s 2007 Free Software Foundation, Inc.\n", + printf ("Copyright %s 2006 Free Software Foundation, Inc.\n", _("(C)")); fputs (_("This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"), @@ -3651,7 +3511,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" else if (strcmp (argv[i], "-Xlinker") == 0) { if (i + 1 == argc) - fatal ("argument to '-Xlinker' is missing"); + fatal ("argument to `-Xlinker' is missing"); n_infiles++; i++; @@ -3659,21 +3519,21 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" else if (strcmp (argv[i], "-Xpreprocessor") == 0) { if (i + 1 == argc) - fatal ("argument to '-Xpreprocessor' is missing"); + fatal ("argument to `-Xpreprocessor' is missing"); add_preprocessor_option (argv[i+1], strlen (argv[i+1])); } else if (strcmp (argv[i], "-Xassembler") == 0) { if (i + 1 == argc) - fatal ("argument to '-Xassembler' is missing"); + fatal ("argument to `-Xassembler' is missing"); add_assembler_option (argv[i+1], strlen (argv[i+1])); } else if (strcmp (argv[i], "-l") == 0) { if (i + 1 == argc) - fatal ("argument to '-l' is missing"); + fatal ("argument to `-l' is missing"); n_infiles++; i++; @@ -3685,16 +3545,11 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" save_temps_flag = 1; n_switches++; } - else if (strcmp (argv[i], "-combine") == 0) - { - combine_flag = 1; - n_switches++; - } else if (strcmp (argv[i], "-specs") == 0) { - struct user_specs *user = XNEW (struct user_specs); + struct user_specs *user = xmalloc (sizeof (struct user_specs)); if (++i >= argc) - fatal ("argument to '-specs' is missing"); + fatal ("argument to `-specs' is missing"); user->next = (struct user_specs *) 0; user->filename = argv[i]; @@ -3706,9 +3561,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } else if (strncmp (argv[i], "-specs=", 7) == 0) { - struct user_specs *user = XNEW (struct user_specs); + struct user_specs *user = xmalloc (sizeof (struct user_specs)); if (strlen (argv[i]) == 7) - fatal ("argument to '-specs=' is missing"); + fatal ("argument to `-specs=' is missing"); user->next = (struct user_specs *) 0; user->filename = argv[i] + 7; @@ -3744,12 +3599,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" switch (c) { case 'b': - if (NULL == strchr(argv[i] + 2, '-')) - goto normal_switch; - - /* Fall through. */ case 'V': - fatal ("'-%c' must come at the start of the command line", c); + fatal ("`-%c' must come at the start of the command line", c); break; case 'B': @@ -3758,7 +3609,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" int len; if (p[1] == 0 && i + 1 == argc) - fatal ("argument to '-B' is missing"); + fatal ("argument to `-B' is missing"); if (p[1] == 0) value = argv[++i]; else @@ -3774,9 +3625,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if appending a directory separator actually makes a valid directory name. */ if (! IS_DIR_SEPARATOR (value [len - 1]) - && is_directory (value, false)) + && is_directory (value, "", 0)) { - char *tmp = XNEWVEC (char, len + 2); + char *tmp = xmalloc (len + 2); strcpy (tmp, value); tmp[len] = DIR_SEPARATOR; tmp[++ len] = 0; @@ -3793,24 +3644,25 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" && (IS_DIR_SEPARATOR (value[len - 1]))) { if (len == 7) - add_prefix (&include_prefixes, "./", NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); + add_prefix (&include_prefixes, "include", NULL, + PREFIX_PRIORITY_B_OPT, 0, NULL, 0); else { - char *string = xmalloc (len - 6); - memcpy (string, value, len - 7); - string[len - 7] = 0; - add_prefix (&include_prefixes, string, NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); + char * string = xmalloc (len + 1); + + strncpy (string, value, len - 7); + strcpy (string + len - 7, "include"); + add_prefix (&include_prefixes, string, NULL, + PREFIX_PRIORITY_B_OPT, 0, NULL, 0); } } add_prefix (&exec_prefixes, value, NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); + PREFIX_PRIORITY_B_OPT, 0, &warn_B, 0); add_prefix (&startfile_prefixes, value, NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); - add_prefix (&include_prefixes, value, NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); + PREFIX_PRIORITY_B_OPT, 0, &warn_B, 0); + add_prefix (&include_prefixes, concat (value, "include", NULL), + NULL, PREFIX_PRIORITY_B_OPT, 0, NULL, 0); n_switches++; } break; @@ -3928,11 +3780,18 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } } - if (save_temps_flag && use_pipes) + combine_inputs = (have_c && have_o && lang_n_infiles > 1); + + if ((save_temps_flag || report_times) && use_pipes) { /* -save-temps overrides -pipe, so that temp files are produced */ if (save_temps_flag) error ("warning: -pipe ignored because -save-temps specified"); + /* -time overrides -pipe because we can't get correct stats when + multiple children are running at once. */ + else if (report_times) + error ("warning: -pipe ignored because -time specified"); + use_pipes = 0; } @@ -3942,23 +3801,31 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" (such as cpp) rather than those of the host system. */ /* Use 2 as fourth arg meaning try just the machine as a suffix, as well as trying the machine and the version. */ +#ifdef FREEBSD_NATIVE + add_prefix (&exec_prefixes, PREFIX"/bin/", "BINUTILS", + PREFIX_PRIORITY_LAST, 0, warn_std_ptr, 0); +#endif /* FREEBSD_NATIVE */ #ifndef OS2 add_prefix (&exec_prefixes, standard_libexec_prefix, "GCC", - PREFIX_PRIORITY_LAST, 1, 0); + PREFIX_PRIORITY_LAST, 1, warn_std_ptr, 0); add_prefix (&exec_prefixes, standard_libexec_prefix, "BINUTILS", - PREFIX_PRIORITY_LAST, 2, 0); + PREFIX_PRIORITY_LAST, 2, warn_std_ptr, 0); +#ifndef FREEBSD_NATIVE add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS", - PREFIX_PRIORITY_LAST, 2, 0); + PREFIX_PRIORITY_LAST, 2, warn_std_ptr, 0); add_prefix (&exec_prefixes, standard_exec_prefix_1, "BINUTILS", - PREFIX_PRIORITY_LAST, 2, 0); + PREFIX_PRIORITY_LAST, 2, warn_std_ptr, 0); add_prefix (&exec_prefixes, standard_exec_prefix_2, "BINUTILS", - PREFIX_PRIORITY_LAST, 2, 0); + PREFIX_PRIORITY_LAST, 2, warn_std_ptr, 0); +#endif /* FREEBSD_NATIVE */ #endif +#ifndef FREEBSD_NATIVE add_prefix (&startfile_prefixes, standard_exec_prefix, "BINUTILS", - PREFIX_PRIORITY_LAST, 1, 0); + PREFIX_PRIORITY_LAST, 1, warn_std_ptr, 0); add_prefix (&startfile_prefixes, standard_exec_prefix_2, "BINUTILS", - PREFIX_PRIORITY_LAST, 1, 0); + PREFIX_PRIORITY_LAST, 1, warn_std_ptr, 0); +#endif /* not FREEBSD_NATIVE */ tooldir_prefix = concat (tooldir_base_prefix, spec_machine, dir_separator_str, NULL); @@ -3981,11 +3848,11 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" add_prefix (&exec_prefixes, concat (gcc_exec_tooldir_prefix, "bin", dir_separator_str, NULL), - NULL, PREFIX_PRIORITY_LAST, 0, 0); + NULL, PREFIX_PRIORITY_LAST, 0, NULL, 0); add_prefix (&startfile_prefixes, concat (gcc_exec_tooldir_prefix, "lib", dir_separator_str, NULL), - NULL, PREFIX_PRIORITY_LAST, 0, 1); + NULL, PREFIX_PRIORITY_LAST, 0, NULL, 1); } tooldir_prefix = concat (standard_exec_prefix, spec_machine, @@ -3993,12 +3860,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" dir_separator_str, tooldir_prefix, NULL); } +#ifndef FREEBSD_NATIVE add_prefix (&exec_prefixes, concat (tooldir_prefix, "bin", dir_separator_str, NULL), - "BINUTILS", PREFIX_PRIORITY_LAST, 0, 0); + "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 0); add_prefix (&startfile_prefixes, concat (tooldir_prefix, "lib", dir_separator_str, NULL), - "BINUTILS", PREFIX_PRIORITY_LAST, 0, 1); + "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1); #if defined(TARGET_SYSTEM_ROOT_RELOCATABLE) && !defined(VMS) /* If the normal TARGET_SYSTEM_ROOT is inside of $exec_prefix, @@ -4017,14 +3885,15 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } } #endif +#endif /* FREEBSD_NATIVE */ /* More prefixes are enabled in main, after we read the specs file and determine whether this is cross-compilation or not. */ /* Then create the space for the vectors and scan again. */ - switches = XNEWVEC (struct switchstr, n_switches + 1); - infiles = XNEWVEC (struct infile, n_infiles + 1); + switches = xmalloc ((n_switches + 1) * sizeof (struct switchstr)); + infiles = xmalloc ((n_infiles + 1) * sizeof (struct infile)); n_switches = 0; n_infiles = 0; last_language_n_infiles = -1; @@ -4071,11 +3940,6 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" ; else if (! strcmp (argv[i], "-fhelp")) ; - else if (! strncmp (argv[i], "--sysroot=", strlen ("--sysroot="))) - { - target_system_root = argv[i] + strlen ("--sysroot="); - target_system_root_changed = 1; - } else if (argv[i][0] == '+' && argv[i][1] == 'e') { /* Compensate for the +e options to the C++ front-end; @@ -4111,12 +3975,16 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" infiles[n_infiles].language = "*"; infiles[n_infiles++].name = argv[++i]; } - /* Xassembler and Xpreprocessor were already handled in the first argv - scan, so all we need to do here is ignore them and their argument. */ else if (strcmp (argv[i], "-Xassembler") == 0) - i++; + { + infiles[n_infiles].language = "*"; + infiles[n_infiles++].name = argv[++i]; + } else if (strcmp (argv[i], "-Xpreprocessor") == 0) - i++; + { + infiles[n_infiles].language = "*"; + infiles[n_infiles++].name = argv[++i]; + } else if (strcmp (argv[i], "-l") == 0) { /* POSIX allows separation of -l and the lib arg; canonicalize by concatenating -l with its arg */ @@ -4144,7 +4012,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (c == 'x') { if (p[1] == 0 && i + 1 == argc) - fatal ("argument to '-x' is missing"); + fatal ("argument to `-x' is missing"); if (p[1] == 0) spec_lang = argv[++i]; else @@ -4172,9 +4040,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0); } if (i + n_args >= argc) - fatal ("argument to '-%s' is missing", p); + fatal ("argument to `-%s' is missing", p); switches[n_switches].args - = XNEWVEC (const char *, n_args + 1); + = xmalloc ((n_args + 1) * sizeof(const char *)); while (j < n_args) switches[n_switches].args[j++] = argv[++i]; /* Null-terminate the vector. */ @@ -4184,12 +4052,12 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" { /* On some systems, ld cannot handle some options without a space. So split the option from its argument. */ - char *part1 = XNEWVEC (char, 2); + char *part1 = xmalloc (2); part1[0] = c; part1[1] = '\0'; switches[n_switches].part1 = part1; - switches[n_switches].args = XNEWVEC (const char *, 2); + switches[n_switches].args = xmalloc (2 * sizeof (const char *)); switches[n_switches].args[0] = xstrdup (p+1); switches[n_switches].args[1] = 0; } @@ -4233,7 +4101,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } if (n_infiles == last_language_n_infiles && spec_lang != 0) - error ("warning: '-x %s' after last input file has no effect", spec_lang); + error ("warning: `-x %s' after last input file has no effect", spec_lang); /* Ensure we only invoke each subprocess once. */ if (target_help_flag || print_help_list) @@ -4324,7 +4192,7 @@ set_collect_gcc_options (void) } } obstack_grow (&collect_obstack, "\0", 1); - putenv (XOBFINISH (&collect_obstack, char *)); + putenv (obstack_finish (&collect_obstack)); } /* Process a spec string, accumulating and running commands. */ @@ -4343,9 +4211,7 @@ static int basename_length; static int suffixed_basename_length; static const char *input_basename; static const char *input_suffix; -#ifndef HOST_LACKS_INODE_NUMBERS static struct stat input_stat; -#endif static int input_stat_set; /* The compiler used to process the current input file. */ @@ -4423,7 +4289,7 @@ do_spec_2 (const char *spec) if (arg_going) { obstack_1grow (&obstack, 0); - string = XOBFINISH (&obstack, const char *); + string = obstack_finish (&obstack); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -4510,7 +4376,7 @@ do_self_spec (const char *spec) /* Each switch should start with '-'. */ if (argbuf[i][0] != '-') - fatal ("switch '%s' does not start with '-'", argbuf[i]); + abort (); sw = &switches[i + first]; sw->part1 = &argbuf[i][1]; @@ -4522,57 +4388,6 @@ do_self_spec (const char *spec) } } -/* Callback for processing %D and %I specs. */ - -struct spec_path_info { - const char *option; - const char *append; - size_t append_len; - bool omit_relative; - bool separate_options; -}; - -static void * -spec_path (char *path, void *data) -{ - struct spec_path_info *info = data; - size_t len = 0; - char save = 0; - - if (info->omit_relative && !IS_ABSOLUTE_PATH (path)) - return NULL; - - if (info->append_len != 0) - { - len = strlen (path); - memcpy (path + len, info->append, info->append_len + 1); - } - - if (!is_directory (path, true)) - return NULL; - - do_spec_1 (info->option, 1, NULL); - if (info->separate_options) - do_spec_1 (" ", 0, NULL); - - if (info->append_len == 0) - { - len = strlen (path); - save = path[len - 1]; - if (IS_DIR_SEPARATOR (path[len - 1])) - path[len - 1] = '\0'; - } - - do_spec_1 (path, 1, NULL); - do_spec_1 (" ", 0, NULL); - - /* Must not damage the original path. */ - if (info->append_len == 0) - path[len - 1] = save; - - return NULL; -} - /* Process the sub-spec SPEC as a portion of a larger spec. This is like processing a whole spec except that we do not initialize at the beginning and we do not supply a @@ -4605,7 +4420,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (arg_going) { obstack_1grow (&obstack, 0); - string = XOBFINISH (&obstack, const char *); + string = obstack_finish (&obstack); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -4650,7 +4465,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (arg_going) { obstack_1grow (&obstack, 0); - string = XOBFINISH (&obstack, const char *); + string = obstack_finish (&obstack); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -4669,7 +4484,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (arg_going) { obstack_1grow (&obstack, 0); - string = XOBFINISH (&obstack, const char *); + string = obstack_finish (&obstack); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -4687,7 +4502,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) switch (c = *p++) { case 0: - fatal ("spec '%s' invalid", spec); + fatal ("invalid specification! Bug in cc"); case 'b': obstack_grow (&obstack, input_basename, basename_length); @@ -4708,23 +4523,111 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) that we search for startfiles. */ case 'D': { - struct spec_path_info info; + struct prefix_list *pl = startfile_prefixes.plist; + size_t bufsize = 100; + char *buffer = xmalloc (bufsize); + int idx; - info.option = "-L"; - info.append_len = 0; + for (; pl; pl = pl->next) + { #ifdef RELATIVE_PREFIX_NOT_LINKDIR - /* Used on systems which record the specified -L dirs - and use them to search for dynamic linking. - Relative directories always come from -B, - and it is better not to use them for searching - at run time. In particular, stage1 loses. */ - info.omit_relative = true; -#else - info.omit_relative = false; + /* Used on systems which record the specified -L dirs + and use them to search for dynamic linking. */ + /* Relative directories always come from -B, + and it is better not to use them for searching + at run time. In particular, stage1 loses. */ + if (!IS_ABSOLUTE_PATH (pl->prefix)) + continue; #endif - info.separate_options = false; + /* Try subdirectory if there is one. */ + if (multilib_dir != NULL + || (pl->os_multilib && multilib_os_dir != NULL)) + { + const char *multi_dir; - for_each_path (&startfile_prefixes, true, 0, spec_path, &info); + multi_dir = pl->os_multilib ? multilib_os_dir + : multilib_dir; + if (machine_suffix && multilib_dir) + { + if (strlen (pl->prefix) + strlen (machine_suffix) + >= bufsize) + bufsize = (strlen (pl->prefix) + + strlen (machine_suffix)) * 2 + 1; + buffer = xrealloc (buffer, bufsize); + strcpy (buffer, pl->prefix); + strcat (buffer, machine_suffix); + if (is_directory (buffer, multilib_dir, 1)) + { + do_spec_1 ("-L", 0, NULL); +#ifdef SPACE_AFTER_L_OPTION + do_spec_1 (" ", 0, NULL); +#endif + do_spec_1 (buffer, 1, NULL); + do_spec_1 (multilib_dir, 1, NULL); + /* Make this a separate argument. */ + do_spec_1 (" ", 0, NULL); + } + } + if (!pl->require_machine_suffix) + { + if (is_directory (pl->prefix, multi_dir, 1)) + { + do_spec_1 ("-L", 0, NULL); +#ifdef SPACE_AFTER_L_OPTION + do_spec_1 (" ", 0, NULL); +#endif + do_spec_1 (pl->prefix, 1, NULL); + do_spec_1 (multi_dir, 1, NULL); + /* Make this a separate argument. */ + do_spec_1 (" ", 0, NULL); + } + } + } + if (machine_suffix) + { + if (is_directory (pl->prefix, machine_suffix, 1)) + { + do_spec_1 ("-L", 0, NULL); +#ifdef SPACE_AFTER_L_OPTION + do_spec_1 (" ", 0, NULL); +#endif + do_spec_1 (pl->prefix, 1, NULL); + /* Remove slash from machine_suffix. */ + if (strlen (machine_suffix) >= bufsize) + bufsize = strlen (machine_suffix) * 2 + 1; + buffer = xrealloc (buffer, bufsize); + strcpy (buffer, machine_suffix); + idx = strlen (buffer); + if (IS_DIR_SEPARATOR (buffer[idx - 1])) + buffer[idx - 1] = 0; + do_spec_1 (buffer, 1, NULL); + /* Make this a separate argument. */ + do_spec_1 (" ", 0, NULL); + } + } + if (!pl->require_machine_suffix) + { + if (is_directory (pl->prefix, "", 1)) + { + do_spec_1 ("-L", 0, NULL); +#ifdef SPACE_AFTER_L_OPTION + do_spec_1 (" ", 0, NULL); +#endif + /* Remove slash from pl->prefix. */ + if (strlen (pl->prefix) >= bufsize) + bufsize = strlen (pl->prefix) * 2 + 1; + buffer = xrealloc (buffer, bufsize); + strcpy (buffer, pl->prefix); + idx = strlen (buffer); + if (IS_DIR_SEPARATOR (buffer[idx - 1])) + buffer[idx - 1] = 0; + do_spec_1 (buffer, 1, NULL); + /* Make this a separate argument. */ + do_spec_1 (" ", 0, NULL); + } + } + } + free (buffer); } break; @@ -4788,7 +4691,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) arg_going = 1; /* consume suffix */ - while (*p == '.' || ISALNUM ((unsigned char) *p)) + while (*p == '.' || ISALPHA ((unsigned char) *p)) p++; if (p[0] == '%' && p[1] == 'O') p += 2; @@ -4800,7 +4703,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (use_pipes) { /* consume suffix */ - while (*p == '.' || ISALNUM ((unsigned char) *p)) + while (*p == '.' || ISALPHA ((unsigned char) *p)) p++; if (p[0] == '%' && p[1] == 'O') p += 2; @@ -4818,21 +4721,21 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) const char *suffix = p; char *saved_suffix = NULL; - while (*p == '.' || ISALNUM ((unsigned char) *p)) + while (*p == '.' || ISALPHA ((unsigned char) *p)) p++; suffix_length = p - suffix; if (p[0] == '%' && p[1] == 'O') { p += 2; /* We don't support extra suffix characters after %O. */ - if (*p == '.' || ISALNUM ((unsigned char) *p)) - fatal ("spec '%s' has invalid '%%0%c'", spec, *p); + if (*p == '.' || ISALPHA ((unsigned char) *p)) + abort (); if (suffix_length == 0) suffix = TARGET_OBJECT_SUFFIX; else { saved_suffix - = XNEWVEC (char, suffix_length + = xmalloc (suffix_length + strlen (TARGET_OBJECT_SUFFIX)); strncpy (saved_suffix, suffix, suffix_length); strcpy (saved_suffix + suffix_length, @@ -4859,7 +4762,6 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) *((char *) temp_filename + temp_filename_length) = '\0'; if (strcmp (temp_filename, input_filename) != 0) { -#ifndef HOST_LACKS_INODE_NUMBERS struct stat st_temp; /* Note, set_input() resets input_stat_set to 0. */ @@ -4874,19 +4776,11 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) and we can do the stat for the temp_filename then the they could still refer to the same file if st_dev/st_ino's are the same. */ + if (input_stat_set != 1 || stat (temp_filename, &st_temp) < 0 || input_stat.st_dev != st_temp.st_dev || input_stat.st_ino != st_temp.st_ino) -#else - /* Just compare canonical pathnames. */ - char* input_realname = lrealpath (input_filename); - char* temp_realname = lrealpath (temp_filename); - bool files_differ = strcmp (input_realname, temp_realname); - free (input_realname); - free (temp_realname); - if (files_differ) -#endif { temp_filename = save_string (temp_filename, temp_filename_length + 1); @@ -4945,12 +4839,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (combine_inputs) { for (i = 0; (int) i < n_infiles; i++) - if ((!infiles[i].language) || (infiles[i].language[0] != '*')) - if (infiles[i].incompiler == input_file_compiler) - { - store_arg (infiles[i].name, 0, 0); - infiles[i].compiled = true; - } + store_arg (infiles[i].name, 0, 0); } else { @@ -4961,16 +4850,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) case 'I': { - struct spec_path_info info; - - if (multilib_dir) - { - do_spec_1 ("-imultilib", 1, NULL); - /* Make this a separate argument. */ - do_spec_1 (" ", 0, NULL); - do_spec_1 (multilib_dir, 1, NULL); - do_spec_1 (" ", 0, NULL); - } + struct prefix_list *pl = include_prefixes.plist; if (gcc_exec_prefix) { @@ -4993,14 +4873,14 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) do_spec_1 (" ", 0, NULL); } - info.option = "-isystem"; - info.append = "include"; - info.append_len = strlen (info.append); - info.omit_relative = false; - info.separate_options = true; - - for_each_path (&include_prefixes, false, info.append_len, - spec_path, &info); + for (; pl; pl = pl->next) + { + do_spec_1 ("-isystem", 1, NULL); + /* Make this a separate argument. */ + do_spec_1 (" ", 0, NULL); + do_spec_1 (pl->prefix, 1, NULL); + do_spec_1 (" ", 0, NULL); + } } break; @@ -5037,7 +4917,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) int cur_index = argbuf_index; /* Handle the {...} following the %W. */ if (*p != '{') - fatal ("spec '%s' has invalid '%%W%c", spec, *p); + abort (); p = handle_braces (p + 1); if (p == 0) return -1; @@ -5045,7 +4925,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (arg_going) { obstack_1grow (&obstack, 0); - string = XOBFINISH (&obstack, const char *); + string = obstack_finish (&obstack); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -5068,7 +4948,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) /* Skip past the option value and make a copy. */ if (*p != '{') - fatal ("spec '%s' has invalid '%%x%c'", spec, *p); + abort (); while (*p++ != '}') ; string = save_string (p1 + 1, p - p1 - 2); @@ -5179,6 +5059,23 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) return value; break; + case 'M': + if (multilib_dir && strcmp (multilib_dir, ".") != 0) + { + char *p; + const char *q; + size_t len; + + len = strlen (multilib_dir); + obstack_blank (&obstack, len + 1); + p = obstack_next_free (&obstack) - (len + 1); + + *p++ = '_'; + for (q = multilib_dir; *q ; ++q, ++p) + *p = (IS_DIR_SEPARATOR (*q) ? '_' : *q); + } + break; + case 'R': /* We assume there is a directory separator at the end of this string. */ @@ -5261,7 +5158,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) } else /* Catch the case where a spec string contains something like - '%{foo:%*}'. i.e. there is no * in the pattern on the left + '%{foo:%*}'. ie there is no * in the pattern on the left hand side of the :. */ error ("spec failure: '%%*' has not been initialized by pattern match"); break; @@ -5374,7 +5271,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (processing_spec_function && arg_going) { obstack_1grow (&obstack, 0); - string = XOBFINISH (&obstack, const char *); + string = obstack_finish (&obstack); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -5391,11 +5288,20 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) static const struct spec_function * lookup_spec_function (const char *name) { + static const struct spec_function * const spec_function_tables[] = + { + static_spec_functions, + lang_specific_spec_functions, + }; const struct spec_function *sf; + unsigned int i; - for (sf = static_spec_functions; sf->name != NULL; sf++) - if (strcmp (sf->name, name) == 0) - return sf; + for (i = 0; i < ARRAY_SIZE (spec_function_tables); i++) + { + for (sf = spec_function_tables[i]; sf->name != NULL; sf++) + if (strcmp (sf->name, name) == 0) + return sf; + } return NULL; } @@ -5423,7 +5329,7 @@ eval_spec_function (const char *func, const char *args) sf = lookup_spec_function (func); if (sf == NULL) - fatal ("unknown spec function '%s'", func); + fatal ("unknown spec function `%s'", func); /* Push the spec processing context. */ save_argbuf_index = argbuf_index; @@ -5442,7 +5348,7 @@ eval_spec_function (const char *func, const char *args) alloc_args (); if (do_spec_2 (args) < 0) - fatal ("error in args to spec function '%s'", func); + fatal ("error in args to spec function `%s'", func); /* argbuf_index is an index for the next argument to be inserted, and so contains the count of the args already inserted. */ @@ -5535,31 +5441,15 @@ handle_spec_function (const char *p) static inline bool input_suffix_matches (const char *atom, const char *end_atom) { - /* We special case the semantics of {.s:...} and {.S:...} and their - negative variants. Instead of testing the input filename suffix, - we test whether the input source file is an assembler file or an - assembler-with-cpp file respectively. This allows us to correctly - handle the -x command line option. */ - - if (atom + 1 == end_atom - && input_file_compiler - && input_file_compiler->suffix) - { - if (*atom == 's') - return !strcmp (input_file_compiler->suffix, "@assembler"); - if (*atom == 'S') - return !strcmp (input_file_compiler->suffix, "@assembler-with-cpp"); - } - return (input_suffix && !strncmp (input_suffix, atom, end_atom - atom) && input_suffix[end_atom - atom] == '\0'); } -/* Subroutine of handle_braces. Returns true if a switch +/* Inline subroutine of handle_braces. Returns true if a switch matching the atom bracketed by ATOM and END_ATOM appeared on the command line. */ -static bool +static inline bool switch_matches (const char *atom, const char *end_atom, int starred) { int i; @@ -5616,7 +5506,6 @@ handle_braces (const char *p) { const char *atom, *end_atom; const char *d_atom = NULL, *d_end_atom = NULL; - const char *orig = p; bool a_is_suffix; bool a_is_starred; @@ -5636,7 +5525,7 @@ handle_braces (const char *p) do { if (a_must_be_last) - goto invalid; + abort (); /* Scan one "atom" (S in the description above of %{}, possibly with !, ., or * modifiers). */ @@ -5660,33 +5549,32 @@ handle_braces (const char *p) p++, a_is_starred = 1; SKIP_WHITE(); - switch (*p) + if (*p == '&' || *p == '}') { - case '&': case '}': /* Substitute the switch(es) indicated by the current atom. */ ordered_set = true; if (disjunct_set || n_way_choice || a_is_negated || a_is_suffix || atom == end_atom) - goto invalid; + abort (); mark_matching_switches (atom, end_atom, a_is_starred); if (*p == '}') process_marked_switches (); - break; - - case '|': case ':': + } + else if (*p == '|' || *p == ':') + { /* Substitute some text if the current atom appears as a switch or suffix. */ disjunct_set = true; if (ordered_set) - goto invalid; + abort (); if (atom == end_atom) { if (!n_way_choice || disj_matched || *p == '|' || a_is_negated || a_is_suffix || a_is_starred) - goto invalid; + abort (); /* An empty term may appear as the last choice of an N-way choice set; it means "otherwise". */ @@ -5697,7 +5585,7 @@ handle_braces (const char *p) else { if (a_is_suffix && a_is_starred) - goto invalid; + abort (); if (!a_is_starred) disj_starred = false; @@ -5740,19 +5628,14 @@ handle_braces (const char *p) d_atom = d_end_atom = NULL; } } - break; - - default: - goto invalid; } + else + abort (); } while (*p++ != '}'); return p; - invalid: - fatal ("braced spec '%s' is invalid at '%c'", orig, *p); - #undef SKIP_WHITE } @@ -5792,7 +5675,7 @@ process_brace_body (const char *p, const char *atom, const char *end_atom, else if (*p == '%' && p[1] == '*' && nesting_level == 1) have_subst = true; else if (*p == '\0') - goto invalid; + abort (); p++; } @@ -5801,7 +5684,7 @@ process_brace_body (const char *p, const char *atom, const char *end_atom, end_body--; if (have_subst && !starred) - goto invalid; + abort (); if (matched) { @@ -5837,9 +5720,6 @@ process_brace_body (const char *p, const char *atom, const char *end_atom, } return p; - - invalid: - fatal ("braced spec body '%s' is invalid", body); } /* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch @@ -5977,42 +5857,65 @@ give_switch (int switchnum, int omit_first_word) static const char * find_file (const char *name) { - char *newname = find_a_file (&startfile_prefixes, name, R_OK, true); + char *newname; + + /* Try multilib_dir if it is defined. */ + if (multilib_os_dir != NULL) + { + newname = find_a_file (&startfile_prefixes, name, R_OK, 1); + + /* If we don't find it in the multi library dir, then fall + through and look for it in the normal places. */ + if (newname != NULL) + return newname; + } + + newname = find_a_file (&startfile_prefixes, name, R_OK, 0); return newname ? newname : name; } /* Determine whether a directory exists. If LINKER, return 0 for - certain fixed names not needed by the linker. */ + certain fixed names not needed by the linker. If not LINKER, it is + only important to return 0 if the host machine has a small ARG_MAX + limit. */ static int -is_directory (const char *path1, bool linker) +is_directory (const char *path1, const char *path2, int linker) { - int len1; - char *path; + int len1 = strlen (path1); + int len2 = strlen (path2); + char *path = alloca (3 + len1 + len2); char *cp; struct stat st; - /* Ensure the string ends with "/.". The resulting path will be a - directory even if the given path is a symbolic link. */ - len1 = strlen (path1); - path = alloca (3 + len1); +#ifndef SMALL_ARG_MAX + if (! linker) + return 1; +#endif + + /* Construct the path from the two parts. Ensure the string ends with "/.". + The resulting path will be a directory even if the given path is a + symbolic link. */ memcpy (path, path1, len1); - cp = path + len1; + memcpy (path + len1, path2, len2); + cp = path + len1 + len2; if (!IS_DIR_SEPARATOR (cp[-1])) *cp++ = DIR_SEPARATOR; *cp++ = '.'; *cp = '\0'; +#ifndef FREEBSD_NATIVE /* Exclude directories that the linker is known to search. */ if (linker - && IS_DIR_SEPARATOR (path[0]) && ((cp - path == 6 - && strncmp (path + 1, "lib", 3) == 0) + && strcmp (path, concat (dir_separator_str, "lib", + dir_separator_str, ".", NULL)) == 0) || (cp - path == 10 - && strncmp (path + 1, "usr", 3) == 0 - && IS_DIR_SEPARATOR (path[4]) - && strncmp (path + 5, "lib", 3) == 0))) + && strcmp (path, concat (dir_separator_str, "usr", + dir_separator_str, "lib", + dir_separator_str, ".", NULL)) == 0))) return 0; +#endif /* FREEBSD_NATIVE */ return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode)); } @@ -6072,15 +5975,14 @@ fatal_error (int signum) kill (getpid (), signum); } -extern int main (int, char **); +extern int main (int, const char **); int -main (int argc, char **argv) +main (int argc, const char **argv) { size_t i; int value; int linker_was_run = 0; - int lang_n_infiles = 0; int num_linker_inputs = 0; char *explicit_link_files; char *specs_file; @@ -6094,18 +5996,11 @@ main (int argc, char **argv) xmalloc_set_program_name (programname); - expandargv (&argc, &argv); - - prune_options (&argc, &argv); - #ifdef GCC_DRIVER_HOST_INITIALIZATION /* Perform host dependent initialization when needed. */ GCC_DRIVER_HOST_INITIALIZATION; #endif - /* Unlock the stdio streams. */ - unlock_std_streams (); - gcc_init_libintl (); if (signal (SIGINT, SIG_IGN) != SIG_IGN) @@ -6142,21 +6037,21 @@ main (int argc, char **argv) obstack_grow (&multilib_obstack, p, strlen (p)); obstack_1grow (&multilib_obstack, 0); - multilib_select = XOBFINISH (&multilib_obstack, const char *); + multilib_select = obstack_finish (&multilib_obstack); q = multilib_matches_raw; while ((p = *q++) != (char *) 0) obstack_grow (&multilib_obstack, p, strlen (p)); obstack_1grow (&multilib_obstack, 0); - multilib_matches = XOBFINISH (&multilib_obstack, const char *); + multilib_matches = obstack_finish (&multilib_obstack); q = multilib_exclusions_raw; while ((p = *q++) != (char *) 0) obstack_grow (&multilib_obstack, p, strlen (p)); obstack_1grow (&multilib_obstack, 0); - multilib_exclusions = XOBFINISH (&multilib_obstack, const char *); + multilib_exclusions = obstack_finish (&multilib_obstack); need_space = FALSE; for (i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++) @@ -6170,7 +6065,7 @@ main (int argc, char **argv) } obstack_1grow (&multilib_obstack, 0); - multilib_defaults = XOBFINISH (&multilib_obstack, const char *); + multilib_defaults = obstack_finish (&multilib_obstack); } /* Set up to remember the pathname of gcc and any options @@ -6179,7 +6074,7 @@ main (int argc, char **argv) obstack_init (&collect_obstack); obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1); obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1); - putenv (XOBFINISH (&collect_obstack, char *)); + putenv (obstack_finish (&collect_obstack)); #ifdef INIT_ENVIRONMENT /* Set up any other necessary machine specific environment variables. */ @@ -6190,7 +6085,7 @@ main (int argc, char **argv) Make a table of specified input files (infiles, n_infiles). Decode switches that are handled locally. */ - process_command (argc, (const char **) argv); + process_command (argc, argv); /* Initialize the vector of specs to just the default. This means one element containing 0s, as a terminator. */ @@ -6201,11 +6096,15 @@ main (int argc, char **argv) /* Read specs from a file if there is one. */ +#ifdef FREEBSD_NATIVE + just_machine_suffix = ""; +#else /* FREEBSD_NATIVE */ machine_suffix = concat (spec_machine, dir_separator_str, spec_version, dir_separator_str, NULL); just_machine_suffix = concat (spec_machine, dir_separator_str, NULL); +#endif /* FREEBSD_NATIVE */ - specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true); + specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, 0); /* Read the specs file unless it is a default one. */ if (specs_file != 0 && strcmp (specs_file, "specs")) read_specs (specs_file, TRUE); @@ -6214,10 +6113,11 @@ main (int argc, char **argv) /* We need to check standard_exec_prefix/just_machine_suffix/specs for any override of as, ld and libraries. */ - specs_file = alloca (strlen (standard_exec_prefix) - + strlen (just_machine_suffix) + sizeof ("specs")); + specs_file = (char *) alloca (strlen (FBSD_DATA_PREFIX) + + strlen (just_machine_suffix) + + sizeof ("specs")); - strcpy (specs_file, standard_exec_prefix); + strcpy (specs_file, FBSD_DATA_PREFIX); strcat (specs_file, just_machine_suffix); strcat (specs_file, "specs"); if (access (specs_file, R_OK) == 0) @@ -6242,7 +6142,7 @@ main (int argc, char **argv) if (*md_exec_prefix) { add_prefix (&exec_prefixes, md_exec_prefix, "GCC", - PREFIX_PRIORITY_LAST, 0, 0); + PREFIX_PRIORITY_LAST, 0, NULL, 0); } } @@ -6251,30 +6151,17 @@ main (int argc, char **argv) && do_spec_2 (sysroot_suffix_spec) == 0) { if (argbuf_index > 1) - error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC"); + error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC."); else if (argbuf_index == 1) target_sysroot_suffix = xstrdup (argbuf[argbuf_index -1]); } -#ifdef HAVE_LD_SYSROOT - /* Pass the --sysroot option to the linker, if it supports that. If - there is a sysroot_suffix_spec, it has already been processed by - this point, so target_system_root really is the system root we - should be using. */ - if (target_system_root) - { - obstack_grow (&obstack, "%(sysroot_spec) ", strlen ("%(sysroot_spec) ")); - obstack_grow0 (&obstack, link_spec, strlen (link_spec)); - set_spec ("link", XOBFINISH (&obstack, const char *)); - } -#endif - /* Process sysroot_hdrs_suffix_spec. */ if (*sysroot_hdrs_suffix_spec != 0 && do_spec_2 (sysroot_hdrs_suffix_spec) == 0) { if (argbuf_index > 1) - error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC"); + error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC."); else if (argbuf_index == 1) target_sysroot_hdrs_suffix = xstrdup (argbuf[argbuf_index -1]); } @@ -6287,19 +6174,23 @@ main (int argc, char **argv) int ndx; for (ndx = 0; ndx < argbuf_index; ndx++) add_sysrooted_prefix (&startfile_prefixes, argbuf[ndx], "BINUTILS", - PREFIX_PRIORITY_LAST, 0, 1); + PREFIX_PRIORITY_LAST, 0, NULL, 1); } /* We should eventually get rid of all these and stick to startfile_prefix_spec exclusively. */ else if (*cross_compile == '0' || target_system_root) { + if (*md_exec_prefix) + add_sysrooted_prefix (&startfile_prefixes, md_exec_prefix, "GCC", + PREFIX_PRIORITY_LAST, 0, NULL, 1); + if (*md_startfile_prefix) add_sysrooted_prefix (&startfile_prefixes, md_startfile_prefix, - "GCC", PREFIX_PRIORITY_LAST, 0, 1); + "GCC", PREFIX_PRIORITY_LAST, 0, NULL, 1); if (*md_startfile_prefix_1) add_sysrooted_prefix (&startfile_prefixes, md_startfile_prefix_1, - "GCC", PREFIX_PRIORITY_LAST, 0, 1); + "GCC", PREFIX_PRIORITY_LAST, 0, NULL, 1); /* If standard_startfile_prefix is relative, base it on standard_exec_prefix. This lets us move the installed tree @@ -6311,29 +6202,31 @@ main (int argc, char **argv) if (IS_ABSOLUTE_PATH (standard_startfile_prefix)) add_sysrooted_prefix (&startfile_prefixes, standard_startfile_prefix, "BINUTILS", - PREFIX_PRIORITY_LAST, 0, 1); + PREFIX_PRIORITY_LAST, 0, NULL, 1); else if (*cross_compile == '0') { if (gcc_exec_prefix) add_prefix (&startfile_prefixes, concat (gcc_exec_prefix, machine_suffix, standard_startfile_prefix, NULL), - NULL, PREFIX_PRIORITY_LAST, 0, 1); + NULL, PREFIX_PRIORITY_LAST, 0, NULL, 1); add_prefix (&startfile_prefixes, concat (standard_exec_prefix, machine_suffix, standard_startfile_prefix, NULL), - NULL, PREFIX_PRIORITY_LAST, 0, 1); + NULL, PREFIX_PRIORITY_LAST, 0, NULL, 1); } - if (*standard_startfile_prefix_1) - add_sysrooted_prefix (&startfile_prefixes, - standard_startfile_prefix_1, "BINUTILS", - PREFIX_PRIORITY_LAST, 0, 1); - if (*standard_startfile_prefix_2) - add_sysrooted_prefix (&startfile_prefixes, - standard_startfile_prefix_2, "BINUTILS", - PREFIX_PRIORITY_LAST, 0, 1); +#ifndef FREEBSD_NATIVE + add_sysrooted_prefix (&startfile_prefixes, standard_startfile_prefix_1, + "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1); + add_sysrooted_prefix (&startfile_prefixes, standard_startfile_prefix_2, + "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1); +#endif /* not FREEBSD_NATIVE */ +#if 0 /* Can cause surprises, and one can use -B./ instead. */ + add_prefix (&startfile_prefixes, "./", NULL, + PREFIX_PRIORITY_LAST, 1, NULL, 0); +#endif } /* Process any user specified specs in the order given on the command @@ -6341,7 +6234,7 @@ main (int argc, char **argv) for (uptr = user_specs_head; uptr; uptr = uptr->next) { char *filename = find_a_file (&startfile_prefixes, uptr->filename, - R_OK, true); + R_OK, 0); read_specs (filename ? filename : uptr->filename, FALSE); } @@ -6363,17 +6256,15 @@ main (int argc, char **argv) for (i = 0; (int) i < n_switches; i++) if (! switches[i].validated) - error ("unrecognized option '-%s'", switches[i].part1); + error ("unrecognized option `-%s'", switches[i].part1); /* Obey some of the options. */ if (print_search_dirs) { printf (_("install: %s%s\n"), standard_exec_prefix, machine_suffix); - printf (_("programs: %s\n"), - build_search_list (&exec_prefixes, "", false, false)); - printf (_("libraries: %s\n"), - build_search_list (&startfile_prefixes, "", false, true)); + printf (_("programs: %s\n"), build_search_list (&exec_prefixes, "", 0)); + printf (_("libraries: %s\n"), build_search_list (&startfile_prefixes, "", 0)); return (0); } @@ -6446,7 +6337,6 @@ main (int argc, char **argv) int n; const char *thrmod; - notice ("Target: %s\n", spec_machine); notice ("Configured with: %s\n", configuration_arguments); #ifdef THREAD_MODEL_SPEC @@ -6456,7 +6346,7 @@ main (int argc, char **argv) obstack_init (&obstack); do_spec_1 (THREAD_MODEL_SPEC, 0, thread_model); obstack_1grow (&obstack, '\0'); - thrmod = XOBFINISH (&obstack, const char *); + thrmod = obstack_finish (&obstack); #else thrmod = thread_model; #endif @@ -6482,113 +6372,41 @@ main (int argc, char **argv) } if (n_infiles == added_libraries) - fatal ("no input files"); + fatal ("No input files specified"); /* Make a place to record the compiler output file names that correspond to the input files. */ i = n_infiles; i += lang_specific_extra_outfiles; - outfiles = XCNEWVEC (const char *, i); + outfiles = xcalloc (i, sizeof (char *)); /* Record which files were specified explicitly as link input. */ - explicit_link_files = XCNEWVEC (char, n_infiles); - - if (combine_flag) - combine_inputs = true; - else - combine_inputs = false; - - for (i = 0; (int) i < n_infiles; i++) - { - const char *name = infiles[i].name; - struct compiler *compiler = lookup_compiler (name, - strlen (name), - infiles[i].language); - - if (compiler && !(compiler->combinable)) - combine_inputs = false; - - if (lang_n_infiles > 0 && compiler != input_file_compiler - && infiles[i].language && infiles[i].language[0] != '*') - infiles[i].incompiler = compiler; - else if (compiler) - { - lang_n_infiles++; - input_file_compiler = compiler; - infiles[i].incompiler = compiler; - } - else - { - /* Since there is no compiler for this input file, assume it is a - linker file. */ - explicit_link_files[i] = 1; - infiles[i].incompiler = NULL; - } - infiles[i].compiled = false; - infiles[i].preprocessed = false; - } - - if (!combine_inputs && have_c && have_o && lang_n_infiles > 1) - fatal ("cannot specify -o with -c or -S with multiple files"); + explicit_link_files = xcalloc (1, n_infiles); - if (combine_flag && save_temps_flag) + if (combine_inputs) { - bool save_combine_inputs = combine_inputs; - /* Must do a separate pre-processing pass for C & Objective-C files, to - obtain individual .i files. */ - - combine_inputs = false; - for (i = 0; (int) i < n_infiles; i++) - { - int this_file_error = 0; - - input_file_number = i; - set_input (infiles[i].name); - if (infiles[i].incompiler - && (infiles[i].incompiler)->needs_preprocessing) - input_file_compiler = infiles[i].incompiler; - else - continue; - - if (input_file_compiler) - { - if (input_file_compiler->spec[0] == '#') - { - error ("%s: %s compiler not installed on this system", - input_filename, &input_file_compiler->spec[1]); - this_file_error = 1; - } - else - { - value = do_spec (input_file_compiler->spec); - infiles[i].preprocessed = true; - if (!have_o_argbuf_index) - fatal ("spec '%s' is invalid", input_file_compiler->spec); - infiles[i].name = argbuf[have_o_argbuf_index]; - infiles[i].incompiler - = lookup_compiler (infiles[i].name, - strlen (infiles[i].name), - infiles[i].language); - - if (value < 0) - this_file_error = 1; - } - } - - if (this_file_error) - { - delete_failure_queue (); - error_count++; - break; - } - clear_failure_queue (); - } - combine_inputs = save_combine_inputs; + int lang_n_infiles = 0; + for (i = 0; (int) i < n_infiles; i++) + { + const char *name = infiles[i].name; + struct compiler *compiler + = lookup_compiler (name, strlen (name), infiles[i].language); + if (compiler == NULL) + error ("%s: linker input file unused because linking not done", + name); + else if (lang_n_infiles > 0 && compiler != input_file_compiler) + fatal ("cannot specify -o with -c or -S and multiple languages"); + else + { + lang_n_infiles++; + input_file_compiler = compiler; + } + } } - - for (i = 0; (int) i < n_infiles; i++) + + for (i = 0; (int) i < (combine_inputs ? 1 : n_infiles); i++) { int this_file_error = 0; @@ -6597,9 +6415,6 @@ main (int argc, char **argv) input_file_number = i; set_input (infiles[i].name); - if (infiles[i].compiled) - continue; - /* Use the same thing in %o, unless cp->spec says otherwise. */ outfiles[i] = input_filename; @@ -6610,8 +6425,6 @@ main (int argc, char **argv) input_file_compiler = lookup_compiler (infiles[i].name, input_filename_length, infiles[i].language); - else - input_file_compiler = infiles[i].incompiler; if (input_file_compiler) { @@ -6626,7 +6439,6 @@ main (int argc, char **argv) else { value = do_spec (input_file_compiler->spec); - infiles[i].compiled = true; if (value < 0) this_file_error = 1; } @@ -6650,21 +6462,11 @@ main (int argc, char **argv) clear_failure_queue (); } - /* Reset the input file name to the first compile/object file name, for use - with %b in LINK_SPEC. We use the first input file that we can find - a compiler to compile it instead of using infiles.language since for - languages other than C we use aliases that we then lookup later. */ + /* Reset the output file name to the first input file name, for use + with %b in LINK_SPEC on a target that prefers not to emit a.out + by default. */ if (n_infiles > 0) - { - int i; - - for (i = 0; i < n_infiles ; i++) - if (infiles[i].language && infiles[i].language[0] != '*') - { - set_input (infiles[i].name); - break; - } - } + set_input (infiles[0].name); if (error_count == 0) { @@ -6690,14 +6492,14 @@ main (int argc, char **argv) /* We'll use ld if we can't find collect2. */ if (! strcmp (linker_name_spec, "collect2")) { - char *s = find_a_file (&exec_prefixes, "collect2", X_OK, false); + char *s = find_a_file (&exec_prefixes, "collect2", X_OK, 0); if (s == NULL) linker_name_spec = "ld"; } /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect. */ - putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH", false); - putenv_from_prefixes (&startfile_prefixes, LIBRARY_PATH_ENV, true); + putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH"); + putenv_from_prefixes (&startfile_prefixes, LIBRARY_PATH_ENV); value = do_spec (link_command_spec); if (value < 0) @@ -6769,7 +6571,7 @@ lookup_compiler (const char *name, size_t length, const char *language) } #if defined (OS2) ||defined (HAVE_DOS_BASED_FILE_SYSTEM) - /* Look again, but case-insensitively this time. */ + /* look again, but case-insensitively this time. */ if (cp < compilers) for (cp = compilers + n_compilers - 1; cp >= compilers; cp--) { @@ -6804,7 +6606,7 @@ lookup_compiler (const char *name, size_t length, const char *language) static char * save_string (const char *s, int len) { - char *result = XNEWVEC (char, len + 1); + char *result = xmalloc (len + 1); memcpy (result, s, len); result[len] = 0; @@ -6825,72 +6627,69 @@ perror_with_name (const char *name) error ("%s: %s", name, xstrerror (errno)); } -/* Output an error message and exit. */ - -void -fancy_abort (const char *file, int line, const char *func) +static void +pfatal_pexecute (const char *errmsg_fmt, const char *errmsg_arg) { - fatal_ice ("internal gcc abort in %s, at %s:%d", func, file, line); + if (errmsg_arg) + { + int save_errno = errno; + + /* Space for trailing '\0' is in %s. */ + char *msg = xmalloc (strlen (errmsg_fmt) + strlen (errmsg_arg)); + sprintf (msg, errmsg_fmt, errmsg_arg); + errmsg_fmt = msg; + + errno = save_errno; + } + + pfatal_with_name (errmsg_fmt); } - + /* Output an error message and exit. */ void -fatal_ice (const char *cmsgid, ...) +fancy_abort (void) { - va_list ap; - - va_start (ap, cmsgid); - - fprintf (stderr, "%s: ", programname); - vfprintf (stderr, _(cmsgid), ap); - va_end (ap); - fprintf (stderr, "\n"); - delete_temp_files (); - exit (pass_exit_codes ? ICE_EXIT_CODE : 1); + fatal ("internal gcc abort"); } + +/* Output an error message and exit. */ void -fatal (const char *cmsgid, ...) +fatal (const char *msgid, ...) { va_list ap; - va_start (ap, cmsgid); + va_start (ap, msgid); fprintf (stderr, "%s: ", programname); - vfprintf (stderr, _(cmsgid), ap); + vfprintf (stderr, _(msgid), ap); va_end (ap); fprintf (stderr, "\n"); delete_temp_files (); exit (1); } -/* The argument is actually c-format, not gcc-internal-format, - but because functions with identical names are used through - the rest of the compiler with gcc-internal-format, we just - need to hope all users of these functions use the common - subset between c-format and gcc-internal-format. */ - void -error (const char *gmsgid, ...) +error (const char *msgid, ...) { va_list ap; - va_start (ap, gmsgid); + va_start (ap, msgid); fprintf (stderr, "%s: ", programname); - vfprintf (stderr, _(gmsgid), ap); + vfprintf (stderr, _(msgid), ap); va_end (ap); fprintf (stderr, "\n"); } static void -notice (const char *cmsgid, ...) +notice (const char *msgid, ...) { va_list ap; - va_start (ap, cmsgid); - vfprintf (stderr, _(cmsgid), ap); + va_start (ap, msgid); + vfprintf (stderr, _(msgid), ap); va_end (ap); } @@ -7043,10 +6842,7 @@ used_arg (const char *p, int len) while (*q != ' ') { if (*q == '\0') - { - invalid_matches: - fatal ("multilib spec '%s' is invalid", multilib_matches); - } + abort (); q++; } matches[i].len = q - matches[i].str; @@ -7055,7 +6851,7 @@ used_arg (const char *p, int len) while (*q != ';' && *q != '\0') { if (*q == ' ') - goto invalid_matches; + abort (); q++; } matches[i].rep_len = q - matches[i].replace; @@ -7069,23 +6865,23 @@ used_arg (const char *p, int len) xmalloc from calling fatal, and prevents us from re-executing this block of code. */ mswitches - = XNEWVEC (struct mswitchstr, n_mdswitches + (n_switches ? n_switches : 1)); + = xmalloc (sizeof (struct mswitchstr) + * (n_mdswitches + (n_switches ? n_switches : 1))); for (i = 0; i < n_switches; i++) - if (switches[i].live_cond != SWITCH_IGNORE) - { - int xlen = strlen (switches[i].part1); - for (j = 0; j < cnt; j++) - if (xlen == matches[j].len - && ! strncmp (switches[i].part1, matches[j].str, xlen)) - { - mswitches[n_mswitches].str = matches[j].replace; - mswitches[n_mswitches].len = matches[j].rep_len; - mswitches[n_mswitches].replace = (char *) 0; - mswitches[n_mswitches].rep_len = 0; - n_mswitches++; - break; - } - } + { + int xlen = strlen (switches[i].part1); + for (j = 0; j < cnt; j++) + if (xlen == matches[j].len + && ! strncmp (switches[i].part1, matches[j].str, xlen)) + { + mswitches[n_mswitches].str = matches[j].replace; + mswitches[n_mswitches].len = matches[j].rep_len; + mswitches[n_mswitches].replace = (char *) 0; + mswitches[n_mswitches].rep_len = 0; + n_mswitches++; + break; + } + } /* Add MULTILIB_DEFAULTS switches too, as long as they were not present on the command line nor any options mutually incompatible with @@ -7196,7 +6992,7 @@ set_multilib_dir (void) { int i = 0; - mdswitches = XNEWVEC (struct mdswitchstr, n_mdswitches); + mdswitches = xmalloc (sizeof (struct mdswitchstr) * n_mdswitches); for (start = multilib_defaults; *start != '\0'; start = end + 1) { while (*start == ' ' || *start == '\t') @@ -7211,7 +7007,7 @@ set_multilib_dir (void) obstack_grow (&multilib_obstack, start, end - start); obstack_1grow (&multilib_obstack, 0); - mdswitches[i].str = XOBFINISH (&multilib_obstack, const char *); + mdswitches[i].str = obstack_finish (&multilib_obstack); mdswitches[i++].len = end - start; if (*end == '\0') @@ -7234,11 +7030,7 @@ set_multilib_dir (void) while (*p != ';') { if (*p == '\0') - { - invalid_exclusions: - fatal ("multilib exclusions '%s' is invalid", - multilib_exclusions); - } + abort (); if (! ok) { @@ -7250,7 +7042,7 @@ set_multilib_dir (void) while (*p != ' ' && *p != ';') { if (*p == '\0') - goto invalid_exclusions; + abort (); ++p; } @@ -7292,11 +7084,7 @@ set_multilib_dir (void) while (*p != ' ') { if (*p == '\0') - { - invalid_select: - fatal ("multilib select '%s' is invalid", - multilib_select); - } + abort (); ++p; } this_path_len = p - this_path; @@ -7308,7 +7096,7 @@ set_multilib_dir (void) while (*p != ';') { if (*p == '\0') - goto invalid_select; + abort (); if (! ok) { @@ -7320,7 +7108,7 @@ set_multilib_dir (void) while (*p != ' ' && *p != ';') { if (*p == '\0') - goto invalid_select; + abort (); ++p; } @@ -7358,7 +7146,7 @@ set_multilib_dir (void) if (this_path_len != 1 || this_path[0] != '.') { - char *new_multilib_dir = XNEWVEC (char, this_path_len + 1); + char *new_multilib_dir = xmalloc (this_path_len + 1); char *q; strncpy (new_multilib_dir, this_path, this_path_len); @@ -7379,7 +7167,7 @@ set_multilib_dir (void) q++; if (q < end) { - char *new_multilib_os_dir = XNEWVEC (char, end - q); + char *new_multilib_os_dir = xmalloc (end - q); memcpy (new_multilib_os_dir, q + 1, end - q - 1); new_multilib_os_dir[end - q - 1] = '\0'; multilib_os_dir = new_multilib_os_dir; @@ -7433,11 +7221,7 @@ print_multilib_info (void) while (*p != ' ') { if (*p == '\0') - { - invalid_select: - fatal ("multilib select '%s' is invalid", multilib_select); - } - + abort (); ++p; } @@ -7471,11 +7255,7 @@ print_multilib_info (void) int mp = 0; if (*e == '\0') - { - invalid_exclusion: - fatal ("multilib exclusion '%s' is invalid", - multilib_exclusions); - } + abort (); if (! m) { @@ -7488,7 +7268,7 @@ print_multilib_info (void) while (*e != ' ' && *e != ';') { if (*e == '\0') - goto invalid_exclusion; + abort (); ++e; } @@ -7499,20 +7279,19 @@ print_multilib_info (void) int len = e - this_arg; if (*q == '\0') - goto invalid_select; + abort (); arg = q; while (*q != ' ' && *q != ';') { if (*q == '\0') - goto invalid_select; + abort (); ++q; } - if (! strncmp (arg, this_arg, - (len < q - arg) ? q - arg : len) - || default_arg (this_arg, e - this_arg)) + if (! strncmp (arg, this_arg, (len < q - arg) ? q - arg : len) || + default_arg (this_arg, e - this_arg)) { mp = 1; break; @@ -7543,8 +7322,7 @@ print_multilib_info (void) if (! skip) { /* If this is a duplicate, skip it. */ - skip = (last_path != 0 - && (unsigned int) (p - this_path) == last_path_len + skip = (last_path != 0 && (unsigned int) (p - this_path) == last_path_len && ! strncmp (last_path, this_path, last_path_len)); last_path = this_path; @@ -7564,7 +7342,7 @@ print_multilib_info (void) const char *arg; if (*q == '\0') - goto invalid_select; + abort (); if (*q == '!') arg = NULL; @@ -7574,7 +7352,7 @@ print_multilib_info (void) while (*q != ' ' && *q != ';') { if (*q == '\0') - goto invalid_select; + abort (); ++q; } @@ -7605,7 +7383,7 @@ print_multilib_info (void) int use_arg; if (*p == '\0') - goto invalid_select; + abort (); if (skip) { @@ -7621,7 +7399,7 @@ print_multilib_info (void) while (*p != ' ' && *p != ';') { if (*p == '\0') - goto invalid_select; + abort (); if (use_arg) putchar (*p); ++p; @@ -7695,161 +7473,3 @@ if_exists_else_spec_function (int argc, const char **argv) return argv[1]; } - -/* replace-outfile built-in spec function. - - This looks for the first argument in the outfiles array's name and - replaces it with the second argument. */ - -static const char * -replace_outfile_spec_function (int argc, const char **argv) -{ - int i; - /* Must have exactly two arguments. */ - if (argc != 2) - abort (); - - for (i = 0; i < n_infiles; i++) - { - if (outfiles[i] && !strcmp (outfiles[i], argv[0])) - outfiles[i] = xstrdup (argv[1]); - } - return NULL; -} - -/* Given two version numbers, compares the two numbers. - A version number must match the regular expression - ([1-9][0-9]*|0)(\.([1-9][0-9]*|0))* -*/ -static int -compare_version_strings (const char *v1, const char *v2) -{ - int rresult; - regex_t r; - - if (regcomp (&r, "^([1-9][0-9]*|0)(\\.([1-9][0-9]*|0))*$", - REG_EXTENDED | REG_NOSUB) != 0) - abort (); - rresult = regexec (&r, v1, 0, NULL, 0); - if (rresult == REG_NOMATCH) - fatal ("invalid version number `%s'", v1); - else if (rresult != 0) - abort (); - rresult = regexec (&r, v2, 0, NULL, 0); - if (rresult == REG_NOMATCH) - fatal ("invalid version number `%s'", v2); - else if (rresult != 0) - abort (); - - return strverscmp (v1, v2); -} - - -/* version_compare built-in spec function. - - This takes an argument of the following form: - - <comparison-op> <arg1> [<arg2>] <switch> <result> - - and produces "result" if the comparison evaluates to true, - and nothing if it doesn't. - - The supported <comparison-op> values are: - - >= true if switch is a later (or same) version than arg1 - !> opposite of >= - < true if switch is an earlier version than arg1 - !< opposite of < - >< true if switch is arg1 or later, and earlier than arg2 - <> true if switch is earlier than arg1 or is arg2 or later - - If the switch is not present, the condition is false unless - the first character of the <comparison-op> is '!'. - - For example, - %:version-compare(>= 10.3 mmacosx-version-min= -lmx) - adds -lmx if -mmacosx-version-min=10.3.9 was passed. */ - -static const char * -version_compare_spec_function (int argc, const char **argv) -{ - int comp1, comp2; - size_t switch_len; - const char *switch_value = NULL; - int nargs = 1, i; - bool result; - - if (argc < 3) - fatal ("too few arguments to %%:version-compare"); - if (argv[0][0] == '\0') - abort (); - if ((argv[0][1] == '<' || argv[0][1] == '>') && argv[0][0] != '!') - nargs = 2; - if (argc != nargs + 3) - fatal ("too many arguments to %%:version-compare"); - - switch_len = strlen (argv[nargs + 1]); - for (i = 0; i < n_switches; i++) - if (!strncmp (switches[i].part1, argv[nargs + 1], switch_len) - && check_live_switch (i, switch_len)) - switch_value = switches[i].part1 + switch_len; - - if (switch_value == NULL) - comp1 = comp2 = -1; - else - { - comp1 = compare_version_strings (switch_value, argv[1]); - if (nargs == 2) - comp2 = compare_version_strings (switch_value, argv[2]); - else - comp2 = -1; /* This value unused. */ - } - - switch (argv[0][0] << 8 | argv[0][1]) - { - case '>' << 8 | '=': - result = comp1 >= 0; - break; - case '!' << 8 | '<': - result = comp1 >= 0 || switch_value == NULL; - break; - case '<' << 8: - result = comp1 < 0; - break; - case '!' << 8 | '>': - result = comp1 < 0 || switch_value == NULL; - break; - case '>' << 8 | '<': - result = comp1 >= 0 && comp2 < 0; - break; - case '<' << 8 | '>': - result = comp1 < 0 || comp2 >= 0; - break; - - default: - fatal ("unknown operator '%s' in %%:version-compare", argv[0]); - } - if (! result) - return NULL; - - return argv[nargs + 2]; -} - -/* %:include builtin spec function. This differs from %include in that it - can be nested inside a spec, and thus be conditionalized. It takes - one argument, the filename, and looks for it in the startfile path. - The result is always NULL, i.e. an empty expansion. */ - -static const char * -include_spec_function (int argc, const char **argv) -{ - char *file; - - if (argc != 1) - abort (); - - file = find_a_file (&startfile_prefixes, argv[0], R_OK, 0); - read_specs (file ? file : argv[0], FALSE); - - return NULL; -} diff --git a/contrib/gcc/ginclude/stdarg.h b/contrib/gcc/ginclude/stdarg.h index c9ddd6b..f178505 100644 --- a/contrib/gcc/ginclude/stdarg.h +++ b/contrib/gcc/ginclude/stdarg.h @@ -14,8 +14,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* As a special exception, if you include this header file into source files compiled by GCC, this header file does not by itself cause diff --git a/contrib/gcc/ginclude/stddef.h b/contrib/gcc/ginclude/stddef.h index 7e61795..03bfbf9 100644 --- a/contrib/gcc/ginclude/stddef.h +++ b/contrib/gcc/ginclude/stddef.h @@ -1,5 +1,4 @@ -/* Copyright (C) 1989, 1997, 1998, 1999, 2000, 2002, 2004 - Free Software Foundation, Inc. +/* Copyright (C) 1989, 1997, 1998, 1999, 2000, 2002 Free Software Foundation, Inc. This file is part of GCC. @@ -15,8 +14,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* As a special exception, if you include this header file into source files compiled by GCC, this header file does not by itself cause @@ -296,7 +295,7 @@ typedef _BSD_RUNE_T_ rune_t; #define _BSD_WCHAR_T_DEFINED_ #define _BSD_RUNE_T_DEFINED_ /* Darwin */ #if defined (__FreeBSD__) && (__FreeBSD__ < 5) -/* Why is this file so hard to maintain properly? In contrast to +/* Why is this file so hard to maintain properly? In constrast to the comment above regarding BSD/386 1.1, on FreeBSD for as long as the symbol has existed, _BSD_RUNE_T_ must not stay defined or redundant typedefs will occur when stdlib.h is included after this file. */ @@ -411,8 +410,16 @@ typedef __WINT_TYPE__ wint_t; #ifdef _STDDEF_H /* Offset of member MEMBER in a struct of type TYPE. */ -#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER) - +#ifndef __cplusplus +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#else +/* The cast to "char &" below avoids problems with user-defined + "operator &", which can appear in a POD type. */ +#define offsetof(TYPE, MEMBER) \ + (__offsetof__ (reinterpret_cast <size_t> \ + (&reinterpret_cast <const volatile char &> \ + (static_cast<TYPE *> (0)->MEMBER)))) +#endif /* C++ */ #endif /* _STDDEF_H was defined this time */ #endif /* !_STDDEF_H && !_STDDEF_H_ && !_ANSI_STDDEF_H && !__STDDEF_H__ diff --git a/contrib/gcc/libgcc2.c b/contrib/gcc/libgcc2.c index 851bdd0..4f45b09 100644 --- a/contrib/gcc/libgcc2.c +++ b/contrib/gcc/libgcc2.c @@ -1,7 +1,7 @@ /* More subroutines needed by GCC output code on some machines. */ /* Compile this one with gcc. */ /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -26,42 +26,33 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is + supposedly valid even though this is a "target" file. */ +#include "auto-host.h" + +/* It is incorrect to include config.h here, because this file is being + compiled for the target, and hence definitions concerning only the host + do not apply. */ #include "tconfig.h" #include "tsystem.h" #include "coretypes.h" #include "tm.h" +/* Don't use `fancy_abort' here even if config.h says to use it. */ +#ifdef abort +#undef abort +#endif + #ifdef HAVE_GAS_HIDDEN #define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) #else #define ATTRIBUTE_HIDDEN #endif -#ifndef MIN_UNITS_PER_WORD -#define MIN_UNITS_PER_WORD UNITS_PER_WORD -#endif - -/* Work out the largest "word" size that we can deal with on this target. */ -#if MIN_UNITS_PER_WORD > 4 -# define LIBGCC2_MAX_UNITS_PER_WORD 8 -#elif (MIN_UNITS_PER_WORD > 2 \ - || (MIN_UNITS_PER_WORD > 1 && LONG_LONG_TYPE_SIZE > 32)) -# define LIBGCC2_MAX_UNITS_PER_WORD 4 -#else -# define LIBGCC2_MAX_UNITS_PER_WORD MIN_UNITS_PER_WORD -#endif - -/* Work out what word size we are using for this compilation. - The value can be set on the command line. */ -#ifndef LIBGCC2_UNITS_PER_WORD -#define LIBGCC2_UNITS_PER_WORD LIBGCC2_MAX_UNITS_PER_WORD -#endif - -#if LIBGCC2_UNITS_PER_WORD <= LIBGCC2_MAX_UNITS_PER_WORD - #include "libgcc2.h" #ifdef DECLARE_LIBRARY_RENAMES @@ -157,12 +148,13 @@ __subvDI3 (DWtype a, DWtype b) #endif #ifdef L_mulvsi3 +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) Wtype __mulvSI3 (Wtype a, Wtype b) { const DWtype w = (DWtype) a * (DWtype) b; - if ((Wtype) (w >> W_TYPE_SIZE) != (Wtype) w >> (W_TYPE_SIZE - 1)) + if ((Wtype) (w >> WORD_SIZE) != (Wtype) w >> (WORD_SIZE - 1)) abort (); return w; @@ -281,6 +273,7 @@ __absvDI2 (DWtype a) #endif #ifdef L_mulvdi3 +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) DWtype __mulvDI3 (DWtype u, DWtype v) { @@ -289,10 +282,10 @@ __mulvDI3 (DWtype u, DWtype v) const DWunion uu = {.ll = u}; const DWunion vv = {.ll = v}; - if (__builtin_expect (uu.s.high == uu.s.low >> (W_TYPE_SIZE - 1), 1)) + if (__builtin_expect (uu.s.high == uu.s.low >> (WORD_SIZE - 1), 1)) { /* u fits in a single Wtype. */ - if (__builtin_expect (vv.s.high == vv.s.low >> (W_TYPE_SIZE - 1), 1)) + if (__builtin_expect (vv.s.high == vv.s.low >> (WORD_SIZE - 1), 1)) { /* v fits in a single Wtype as well. */ /* A single multiplication. No overflow risk. */ @@ -311,7 +304,7 @@ __mulvDI3 (DWtype u, DWtype v) if (uu.s.low < 0) w1.ll -= vv.ll; w1.ll += (UWtype) w0.s.high; - if (__builtin_expect (w1.s.high == w1.s.low >> (W_TYPE_SIZE - 1), 1)) + if (__builtin_expect (w1.s.high == w1.s.low >> (WORD_SIZE - 1), 1)) { w0.s.high = w1.s.low; return w0.ll; @@ -320,7 +313,7 @@ __mulvDI3 (DWtype u, DWtype v) } else { - if (__builtin_expect (vv.s.high == vv.s.low >> (W_TYPE_SIZE - 1), 1)) + if (__builtin_expect (vv.s.high == vv.s.low >> (WORD_SIZE - 1), 1)) { /* v fits into a single Wtype. */ /* Two multiplications. */ @@ -334,7 +327,7 @@ __mulvDI3 (DWtype u, DWtype v) if (vv.s.low < 0) w1.ll -= uu.ll; w1.ll += (UWtype) w0.s.high; - if (__builtin_expect (w1.s.high == w1.s.low >> (W_TYPE_SIZE - 1), 1)) + if (__builtin_expect (w1.s.high == w1.s.low >> (WORD_SIZE - 1), 1)) { w0.s.high = w1.s.low; return w0.ll; @@ -494,6 +487,7 @@ __ashrdi3 (DWtype u, word_type b) #ifdef L_ffssi2 #undef int +extern int __ffsSI2 (UWtype u); int __ffsSI2 (UWtype u) { @@ -509,6 +503,7 @@ __ffsSI2 (UWtype u) #ifdef L_ffsdi2 #undef int +extern int __ffsDI2 (DWtype u); int __ffsDI2 (DWtype u) { @@ -565,16 +560,16 @@ __udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d) { if (a1 < d - a1 - (a0 >> (W_TYPE_SIZE - 1))) { - /* Dividend, divisor, and quotient are nonnegative. */ + /* dividend, divisor, and quotient are nonnegative */ sdiv_qrnnd (q, r, a1, a0, d); } else { - /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d. */ + /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */ sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (W_TYPE_SIZE - 1)); - /* Divide (c1*2^32 + c0) by d. */ + /* Divide (c1*2^32 + c0) by d */ sdiv_qrnnd (q, r, c1, c0, d); - /* Add 2^31 to quotient. */ + /* Add 2^31 to quotient */ q += (UWtype) 1 << (W_TYPE_SIZE - 1); } } @@ -670,7 +665,7 @@ __udiv_w_sdiv (UWtype *rp __attribute__ ((__unused__)), #endif #ifdef L_clz -const UQItype __clz_tab[256] = +const UQItype __clz_tab[] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, @@ -679,12 +674,13 @@ const UQItype __clz_tab[256] = 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, }; #endif #ifdef L_clzsi2 #undef int +extern int __clzSI2 (UWtype x); int __clzSI2 (UWtype x) { @@ -698,6 +694,7 @@ __clzSI2 (UWtype x) #ifdef L_clzdi2 #undef int +extern int __clzDI2 (UDWtype x); int __clzDI2 (UDWtype x) { @@ -717,6 +714,7 @@ __clzDI2 (UDWtype x) #ifdef L_ctzsi2 #undef int +extern int __ctzSI2 (UWtype x); int __ctzSI2 (UWtype x) { @@ -730,6 +728,7 @@ __ctzSI2 (UWtype x) #ifdef L_ctzdi2 #undef int +extern int __ctzDI2 (UDWtype x); int __ctzDI2 (UDWtype x) { @@ -747,8 +746,13 @@ __ctzDI2 (UDWtype x) } #endif +#if (defined (L_popcountsi2) || defined (L_popcountdi2) \ + || defined (L_popcount_tab)) +extern const UQItype __popcount_tab[] ATTRIBUTE_HIDDEN; +#endif + #ifdef L_popcount_tab -const UQItype __popcount_tab[256] = +const UQItype __popcount_tab[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, @@ -757,16 +761,17 @@ const UQItype __popcount_tab[256] = 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, - 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, }; #endif #ifdef L_popcountsi2 #undef int +extern int __popcountSI2 (UWtype x); int __popcountSI2 (UWtype x) { - int i, ret = 0; + UWtype i, ret = 0; for (i = 0; i < W_TYPE_SIZE; i += 8) ret += __popcount_tab[(x >> i) & 0xff]; @@ -777,10 +782,11 @@ __popcountSI2 (UWtype x) #ifdef L_popcountdi2 #undef int +extern int __popcountDI2 (UDWtype x); int __popcountDI2 (UDWtype x) { - int i, ret = 0; + UWtype i, ret = 0; for (i = 0; i < 2*W_TYPE_SIZE; i += 8) ret += __popcount_tab[(x >> i) & 0xff]; @@ -791,6 +797,7 @@ __popcountDI2 (UDWtype x) #ifdef L_paritysi2 #undef int +extern int __paritySI2 (UWtype x); int __paritySI2 (UWtype x) { @@ -812,6 +819,7 @@ __paritySI2 (UWtype x) #ifdef L_paritydi2 #undef int +extern int __parityDI2 (UDWtype x); int __parityDI2 (UDWtype x) { @@ -1093,7 +1101,7 @@ __moddi3 (DWtype u, DWtype v) if (vv.s.high < 0) vv.ll = -vv.ll; - (void) __udivmoddi4 (uu.ll, vv.ll, (UDWtype*)&w); + (void) __udivmoddi4 (uu.ll, vv.ll, &w); if (c) w = -w; @@ -1159,7 +1167,10 @@ __ucmpdi2 (DWtype a, DWtype b) } #endif -#if defined(L_fixunstfdi) && LIBGCC2_HAS_TF_MODE +#if defined(L_fixunstfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128) +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) +#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) + DWtype __fixunstfDI (TFtype a) { @@ -1167,11 +1178,11 @@ __fixunstfDI (TFtype a) return 0; /* Compute high word of result, as a flonum. */ - const TFtype b = (a / Wtype_MAXp1_F); + const TFtype b = (a / HIGH_WORD_COEFF); /* Convert that to fixed (but not to DWtype!), and shift it into the high word. */ UDWtype v = (UWtype) b; - v <<= W_TYPE_SIZE; + v <<= WORD_SIZE; /* Remove high part from the TFtype, leaving the low part as flonum. */ a -= (TFtype)v; /* Convert that to fixed (but not to DWtype!) and add it in. @@ -1185,7 +1196,7 @@ __fixunstfDI (TFtype a) } #endif -#if defined(L_fixtfdi) && LIBGCC2_HAS_TF_MODE +#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128) DWtype __fixtfdi (TFtype a) { @@ -1195,7 +1206,10 @@ __fixtfdi (TFtype a) } #endif -#if defined(L_fixunsxfdi) && LIBGCC2_HAS_XF_MODE +#if defined(L_fixunsxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96) +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) +#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) + DWtype __fixunsxfDI (XFtype a) { @@ -1203,11 +1217,11 @@ __fixunsxfDI (XFtype a) return 0; /* Compute high word of result, as a flonum. */ - const XFtype b = (a / Wtype_MAXp1_F); + const XFtype b = (a / HIGH_WORD_COEFF); /* Convert that to fixed (but not to DWtype!), and shift it into the high word. */ UDWtype v = (UWtype) b; - v <<= W_TYPE_SIZE; + v <<= WORD_SIZE; /* Remove high part from the XFtype, leaving the low part as flonum. */ a -= (XFtype)v; /* Convert that to fixed (but not to DWtype!) and add it in. @@ -1221,7 +1235,7 @@ __fixunsxfDI (XFtype a) } #endif -#if defined(L_fixxfdi) && LIBGCC2_HAS_XF_MODE +#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96) DWtype __fixxfdi (XFtype a) { @@ -1231,26 +1245,29 @@ __fixxfdi (XFtype a) } #endif -#if defined(L_fixunsdfdi) && LIBGCC2_HAS_DF_MODE +#ifdef L_fixunsdfdi +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) +#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) + DWtype __fixunsdfDI (DFtype a) { /* Get high part of result. The division here will just moves the radix point and will not cause any rounding. Then the conversion to integral type chops result as desired. */ - const UWtype hi = a / Wtype_MAXp1_F; + const UWtype hi = a / HIGH_WORD_COEFF; /* Get low part of result. Convert `hi' to floating type and scale it back, then subtract this from the number being converted. This leaves the low part. Convert that to integral type. */ - const UWtype lo = a - (DFtype) hi * Wtype_MAXp1_F; + const UWtype lo = (a - ((DFtype) hi) * HIGH_WORD_COEFF); /* Assemble result from the two parts. */ - return ((UDWtype) hi << W_TYPE_SIZE) | lo; + return ((UDWtype) hi << WORD_SIZE) | lo; } #endif -#if defined(L_fixdfdi) && LIBGCC2_HAS_DF_MODE +#ifdef L_fixdfdi DWtype __fixdfdi (DFtype a) { @@ -1260,71 +1277,34 @@ __fixdfdi (DFtype a) } #endif -#if defined(L_fixunssfdi) && LIBGCC2_HAS_SF_MODE +#ifdef L_fixunssfdi +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) +#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) + DWtype -__fixunssfDI (SFtype a) +__fixunssfDI (SFtype original_a) { -#if LIBGCC2_HAS_DF_MODE /* Convert the SFtype to a DFtype, because that is surely not going to lose any bits. Some day someone else can write a faster version that avoids converting to DFtype, and verify it really works right. */ - const DFtype dfa = a; + const DFtype a = original_a; /* Get high part of result. The division here will just moves the radix point and will not cause any rounding. Then the conversion to integral type chops result as desired. */ - const UWtype hi = dfa / Wtype_MAXp1_F; + const UWtype hi = a / HIGH_WORD_COEFF; /* Get low part of result. Convert `hi' to floating type and scale it back, then subtract this from the number being converted. This leaves the low part. Convert that to integral type. */ - const UWtype lo = dfa - (DFtype) hi * Wtype_MAXp1_F; + const UWtype lo = (a - ((DFtype) hi) * HIGH_WORD_COEFF); /* Assemble result from the two parts. */ - return ((UDWtype) hi << W_TYPE_SIZE) | lo; -#elif FLT_MANT_DIG < W_TYPE_SIZE - if (a < 1) - return 0; - if (a < Wtype_MAXp1_F) - return (UWtype)a; - if (a < Wtype_MAXp1_F * Wtype_MAXp1_F) - { - /* Since we know that there are fewer significant bits in the SFmode - quantity than in a word, we know that we can convert out all the - significant bits in one step, and thus avoid losing bits. */ - - /* ??? This following loop essentially performs frexpf. If we could - use the real libm function, or poke at the actual bits of the fp - format, it would be significantly faster. */ - - UWtype shift = 0, counter; - SFtype msb; - - a /= Wtype_MAXp1_F; - for (counter = W_TYPE_SIZE / 2; counter != 0; counter >>= 1) - { - SFtype counterf = (UWtype)1 << counter; - if (a >= counterf) - { - shift |= counter; - a /= counterf; - } - } - - /* Rescale into the range of one word, extract the bits of that - one word, and shift the result into position. */ - a *= Wtype_MAXp1_F; - counter = a; - return (DWtype)counter << shift; - } - return -1; -#else -# error -#endif + return ((UDWtype) hi << WORD_SIZE) | lo; } #endif -#if defined(L_fixsfdi) && LIBGCC2_HAS_SF_MODE +#ifdef L_fixsfdi DWtype __fixsfdi (SFtype a) { @@ -1334,280 +1314,102 @@ __fixsfdi (SFtype a) } #endif -#if defined(L_floatdixf) && LIBGCC2_HAS_XF_MODE +#if defined(L_floatdixf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96) +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) +#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2)) +#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) + XFtype __floatdixf (DWtype u) { -#if W_TYPE_SIZE > XF_SIZE -# error -#endif - XFtype d = (Wtype) (u >> W_TYPE_SIZE); - d *= Wtype_MAXp1_F; - d += (UWtype)u; - return d; -} -#endif + XFtype d = (Wtype) (u >> WORD_SIZE); + d *= HIGH_HALFWORD_COEFF; + d *= HIGH_HALFWORD_COEFF; + d += (UWtype) (u & (HIGH_WORD_COEFF - 1)); -#if defined(L_floatundixf) && LIBGCC2_HAS_XF_MODE -XFtype -__floatundixf (UDWtype u) -{ -#if W_TYPE_SIZE > XF_SIZE -# error -#endif - XFtype d = (UWtype) (u >> W_TYPE_SIZE); - d *= Wtype_MAXp1_F; - d += (UWtype)u; return d; } #endif -#if defined(L_floatditf) && LIBGCC2_HAS_TF_MODE +#if defined(L_floatditf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128) +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) +#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2)) +#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) + TFtype __floatditf (DWtype u) { -#if W_TYPE_SIZE > TF_SIZE -# error -#endif - TFtype d = (Wtype) (u >> W_TYPE_SIZE); - d *= Wtype_MAXp1_F; - d += (UWtype)u; - return d; -} -#endif + TFtype d = (Wtype) (u >> WORD_SIZE); + d *= HIGH_HALFWORD_COEFF; + d *= HIGH_HALFWORD_COEFF; + d += (UWtype) (u & (HIGH_WORD_COEFF - 1)); -#if defined(L_floatunditf) && LIBGCC2_HAS_TF_MODE -TFtype -__floatunditf (UDWtype u) -{ -#if W_TYPE_SIZE > TF_SIZE -# error -#endif - TFtype d = (UWtype) (u >> W_TYPE_SIZE); - d *= Wtype_MAXp1_F; - d += (UWtype)u; return d; } #endif -#if (defined(L_floatdisf) && LIBGCC2_HAS_SF_MODE) \ - || (defined(L_floatdidf) && LIBGCC2_HAS_DF_MODE) -#define DI_SIZE (W_TYPE_SIZE * 2) -#define F_MODE_OK(SIZE) \ - (SIZE < DI_SIZE \ - && SIZE > (DI_SIZE - SIZE + FSSIZE) \ - /* Don't use IBM Extended Double TFmode for TI->SF calculations. \ - The conversion from long double to float suffers from double \ - rounding, because we convert via double. In any case, the \ - fallback code is faster. */ \ - && !IS_IBM_EXTENDED (SIZE)) -#if defined(L_floatdisf) -#define FUNC __floatdisf -#define FSTYPE SFtype -#define FSSIZE SF_SIZE -#else -#define FUNC __floatdidf -#define FSTYPE DFtype -#define FSSIZE DF_SIZE -#endif - -FSTYPE -FUNC (DWtype u) -{ -#if FSSIZE >= W_TYPE_SIZE - /* When the word size is small, we never get any rounding error. */ - FSTYPE f = (Wtype) (u >> W_TYPE_SIZE); - f *= Wtype_MAXp1_F; - f += (UWtype)u; - return f; -#elif (LIBGCC2_HAS_DF_MODE && F_MODE_OK (DF_SIZE)) \ - || (LIBGCC2_HAS_XF_MODE && F_MODE_OK (XF_SIZE)) \ - || (LIBGCC2_HAS_TF_MODE && F_MODE_OK (TF_SIZE)) - -#if (LIBGCC2_HAS_DF_MODE && F_MODE_OK (DF_SIZE)) -# define FSIZE DF_SIZE -# define FTYPE DFtype -#elif (LIBGCC2_HAS_XF_MODE && F_MODE_OK (XF_SIZE)) -# define FSIZE XF_SIZE -# define FTYPE XFtype -#elif (LIBGCC2_HAS_TF_MODE && F_MODE_OK (TF_SIZE)) -# define FSIZE TF_SIZE -# define FTYPE TFtype -#else -# error -#endif - -#define REP_BIT ((UDWtype) 1 << (DI_SIZE - FSIZE)) - - /* Protect against double-rounding error. - Represent any low-order bits, that might be truncated by a bit that - won't be lost. The bit can go in anywhere below the rounding position - of the FSTYPE. A fixed mask and bit position handles all usual - configurations. */ - if (! (- ((DWtype) 1 << FSIZE) < u - && u < ((DWtype) 1 << FSIZE))) - { - if ((UDWtype) u & (REP_BIT - 1)) - { - u &= ~ (REP_BIT - 1); - u |= REP_BIT; - } - } +#ifdef L_floatdidf +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) +#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2)) +#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) - /* Do the calculation in a wider type so that we don't lose any of - the precision of the high word while multiplying it. */ - FTYPE f = (Wtype) (u >> W_TYPE_SIZE); - f *= Wtype_MAXp1_F; - f += (UWtype)u; - return (FSTYPE) f; -#else -#if FSSIZE >= W_TYPE_SIZE - 2 -# error -#endif - /* Finally, the word size is larger than the number of bits in the - required FSTYPE, and we've got no suitable wider type. The only - way to avoid double rounding is to special case the - extraction. */ - - /* If there are no high bits set, fall back to one conversion. */ - if ((Wtype)u == u) - return (FSTYPE)(Wtype)u; - - /* Otherwise, find the power of two. */ - Wtype hi = u >> W_TYPE_SIZE; - if (hi < 0) - hi = -hi; - - UWtype count, shift; - count_leading_zeros (count, hi); - - /* No leading bits means u == minimum. */ - if (count == 0) - return -(Wtype_MAXp1_F * (Wtype_MAXp1_F / 2)); - - shift = 1 + W_TYPE_SIZE - count; - - /* Shift down the most significant bits. */ - hi = u >> shift; - - /* If we lost any nonzero bits, set the lsb to ensure correct rounding. */ - if (u & (((DWtype)1 << shift) - 1)) - hi |= 1; +DFtype +__floatdidf (DWtype u) +{ + DFtype d = (Wtype) (u >> WORD_SIZE); + d *= HIGH_HALFWORD_COEFF; + d *= HIGH_HALFWORD_COEFF; + d += (UWtype) (u & (HIGH_WORD_COEFF - 1)); - /* Convert the one word of data, and rescale. */ - FSTYPE f = hi; - f *= (UDWtype)1 << shift; - return f; -#endif + return d; } #endif -#if (defined(L_floatundisf) && LIBGCC2_HAS_SF_MODE) \ - || (defined(L_floatundidf) && LIBGCC2_HAS_DF_MODE) -#define DI_SIZE (W_TYPE_SIZE * 2) -#define F_MODE_OK(SIZE) \ - (SIZE < DI_SIZE \ - && SIZE > (DI_SIZE - SIZE + FSSIZE) \ - /* Don't use IBM Extended Double TFmode for TI->SF calculations. \ - The conversion from long double to float suffers from double \ - rounding, because we convert via double. In any case, the \ - fallback code is faster. */ \ - && !IS_IBM_EXTENDED (SIZE)) -#if defined(L_floatundisf) -#define FUNC __floatundisf -#define FSTYPE SFtype -#define FSSIZE SF_SIZE -#else -#define FUNC __floatundidf -#define FSTYPE DFtype -#define FSSIZE DF_SIZE -#endif - -FSTYPE -FUNC (UDWtype u) -{ -#if FSSIZE >= W_TYPE_SIZE - /* When the word size is small, we never get any rounding error. */ - FSTYPE f = (UWtype) (u >> W_TYPE_SIZE); - f *= Wtype_MAXp1_F; - f += (UWtype)u; - return f; -#elif (LIBGCC2_HAS_DF_MODE && F_MODE_OK (DF_SIZE)) \ - || (LIBGCC2_HAS_XF_MODE && F_MODE_OK (XF_SIZE)) \ - || (LIBGCC2_HAS_TF_MODE && F_MODE_OK (TF_SIZE)) - -#if (LIBGCC2_HAS_DF_MODE && F_MODE_OK (DF_SIZE)) -# define FSIZE DF_SIZE -# define FTYPE DFtype -#elif (LIBGCC2_HAS_XF_MODE && F_MODE_OK (XF_SIZE)) -# define FSIZE XF_SIZE -# define FTYPE XFtype -#elif (LIBGCC2_HAS_TF_MODE && F_MODE_OK (TF_SIZE)) -# define FSIZE TF_SIZE -# define FTYPE TFtype -#else -# error -#endif +#ifdef L_floatdisf +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) +#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2)) +#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) -#define REP_BIT ((UDWtype) 1 << (DI_SIZE - FSIZE)) +#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT) +#define DF_SIZE DBL_MANT_DIG +#define SF_SIZE FLT_MANT_DIG +SFtype +__floatdisf (DWtype u) +{ /* Protect against double-rounding error. - Represent any low-order bits, that might be truncated by a bit that - won't be lost. The bit can go in anywhere below the rounding position - of the FSTYPE. A fixed mask and bit position handles all usual - configurations. */ - if (u >= ((UDWtype) 1 << FSIZE)) + Represent any low-order bits, that might be truncated in DFmode, + by a bit that won't be lost. The bit can go in anywhere below the + rounding position of the SFmode. A fixed mask and bit position + handles all usual configurations. It doesn't handle the case + of 128-bit DImode, however. */ + if (DF_SIZE < DI_SIZE + && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE)) { - if ((UDWtype) u & (REP_BIT - 1)) +#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE)) + if (! (- ((DWtype) 1 << DF_SIZE) < u + && u < ((DWtype) 1 << DF_SIZE))) { - u &= ~ (REP_BIT - 1); - u |= REP_BIT; + if ((UDWtype) u & (REP_BIT - 1)) + { + u &= ~ (REP_BIT - 1); + u |= REP_BIT; + } } } + /* Do the calculation in DFmode + so that we don't lose any of the precision of the high word + while multiplying it. */ + DFtype f = (Wtype) (u >> WORD_SIZE); + f *= HIGH_HALFWORD_COEFF; + f *= HIGH_HALFWORD_COEFF; + f += (UWtype) (u & (HIGH_WORD_COEFF - 1)); - /* Do the calculation in a wider type so that we don't lose any of - the precision of the high word while multiplying it. */ - FTYPE f = (UWtype) (u >> W_TYPE_SIZE); - f *= Wtype_MAXp1_F; - f += (UWtype)u; - return (FSTYPE) f; -#else -#if FSSIZE == W_TYPE_SIZE - 1 -# error -#endif - /* Finally, the word size is larger than the number of bits in the - required FSTYPE, and we've got no suitable wider type. The only - way to avoid double rounding is to special case the - extraction. */ - - /* If there are no high bits set, fall back to one conversion. */ - if ((UWtype)u == u) - return (FSTYPE)(UWtype)u; - - /* Otherwise, find the power of two. */ - UWtype hi = u >> W_TYPE_SIZE; - - UWtype count, shift; - count_leading_zeros (count, hi); - - shift = W_TYPE_SIZE - count; - - /* Shift down the most significant bits. */ - hi = u >> shift; - - /* If we lost any nonzero bits, set the lsb to ensure correct rounding. */ - if (u & (((UDWtype)1 << shift) - 1)) - hi |= 1; - - /* Convert the one word of data, and rescale. */ - FSTYPE f = hi; - f *= (UDWtype)1 << shift; - return f; -#endif + return (SFtype) f; } #endif -#if defined(L_fixunsxfsi) && LIBGCC2_HAS_XF_MODE +#if defined(L_fixunsxfsi) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96 /* Reenable the normal types, in case limits.h needs them. */ #undef char #undef short @@ -1629,7 +1431,7 @@ __fixunsxfSI (XFtype a) } #endif -#if defined(L_fixunsdfsi) && LIBGCC2_HAS_DF_MODE +#ifdef L_fixunsdfsi /* Reenable the normal types, in case limits.h needs them. */ #undef char #undef short @@ -1651,7 +1453,7 @@ __fixunsdfSI (DFtype a) } #endif -#if defined(L_fixunssfsi) && LIBGCC2_HAS_SF_MODE +#ifdef L_fixunssfsi /* Reenable the normal types, in case limits.h needs them. */ #undef char #undef short @@ -1673,245 +1475,6 @@ __fixunssfSI (SFtype a) } #endif -/* Integer power helper used from __builtin_powi for non-constant - exponents. */ - -#if (defined(L_powisf2) && LIBGCC2_HAS_SF_MODE) \ - || (defined(L_powidf2) && LIBGCC2_HAS_DF_MODE) \ - || (defined(L_powixf2) && LIBGCC2_HAS_XF_MODE) \ - || (defined(L_powitf2) && LIBGCC2_HAS_TF_MODE) -# if defined(L_powisf2) -# define TYPE SFtype -# define NAME __powisf2 -# elif defined(L_powidf2) -# define TYPE DFtype -# define NAME __powidf2 -# elif defined(L_powixf2) -# define TYPE XFtype -# define NAME __powixf2 -# elif defined(L_powitf2) -# define TYPE TFtype -# define NAME __powitf2 -# endif - -#undef int -#undef unsigned -TYPE -NAME (TYPE x, int m) -{ - unsigned int n = m < 0 ? -m : m; - TYPE y = n % 2 ? x : 1; - while (n >>= 1) - { - x = x * x; - if (n % 2) - y = y * x; - } - return m < 0 ? 1/y : y; -} - -#endif - -#if ((defined(L_mulsc3) || defined(L_divsc3)) && LIBGCC2_HAS_SF_MODE) \ - || ((defined(L_muldc3) || defined(L_divdc3)) && LIBGCC2_HAS_DF_MODE) \ - || ((defined(L_mulxc3) || defined(L_divxc3)) && LIBGCC2_HAS_XF_MODE) \ - || ((defined(L_multc3) || defined(L_divtc3)) && LIBGCC2_HAS_TF_MODE) - -#undef float -#undef double -#undef long - -#if defined(L_mulsc3) || defined(L_divsc3) -# define MTYPE SFtype -# define CTYPE SCtype -# define MODE sc -# define CEXT f -# define NOTRUNC __FLT_EVAL_METHOD__ == 0 -#elif defined(L_muldc3) || defined(L_divdc3) -# define MTYPE DFtype -# define CTYPE DCtype -# define MODE dc -# if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 64 -# define CEXT l -# define NOTRUNC 1 -# else -# define CEXT -# define NOTRUNC __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 1 -# endif -#elif defined(L_mulxc3) || defined(L_divxc3) -# define MTYPE XFtype -# define CTYPE XCtype -# define MODE xc -# define CEXT l -# define NOTRUNC 1 -#elif defined(L_multc3) || defined(L_divtc3) -# define MTYPE TFtype -# define CTYPE TCtype -# define MODE tc -# define CEXT l -# define NOTRUNC 1 -#else -# error -#endif - -#define CONCAT3(A,B,C) _CONCAT3(A,B,C) -#define _CONCAT3(A,B,C) A##B##C - -#define CONCAT2(A,B) _CONCAT2(A,B) -#define _CONCAT2(A,B) A##B - -/* All of these would be present in a full C99 implementation of <math.h> - and <complex.h>. Our problem is that only a few systems have such full - implementations. Further, libgcc_s.so isn't currently linked against - libm.so, and even for systems that do provide full C99, the extra overhead - of all programs using libgcc having to link against libm. So avoid it. */ - -#define isnan(x) __builtin_expect ((x) != (x), 0) -#define isfinite(x) __builtin_expect (!isnan((x) - (x)), 1) -#define isinf(x) __builtin_expect (!isnan(x) & !isfinite(x), 0) - -#define INFINITY CONCAT2(__builtin_inf, CEXT) () -#define I 1i - -/* Helpers to make the following code slightly less gross. */ -#define COPYSIGN CONCAT2(__builtin_copysign, CEXT) -#define FABS CONCAT2(__builtin_fabs, CEXT) - -/* Verify that MTYPE matches up with CEXT. */ -extern void *compile_type_assert[sizeof(INFINITY) == sizeof(MTYPE) ? 1 : -1]; - -/* Ensure that we've lost any extra precision. */ -#if NOTRUNC -# define TRUNC(x) -#else -# define TRUNC(x) __asm__ ("" : "=m"(x) : "m"(x)) -#endif - -#if defined(L_mulsc3) || defined(L_muldc3) \ - || defined(L_mulxc3) || defined(L_multc3) - -CTYPE -CONCAT3(__mul,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d) -{ - MTYPE ac, bd, ad, bc, x, y; - - ac = a * c; - bd = b * d; - ad = a * d; - bc = b * c; - - TRUNC (ac); - TRUNC (bd); - TRUNC (ad); - TRUNC (bc); - - x = ac - bd; - y = ad + bc; - - if (isnan (x) && isnan (y)) - { - /* Recover infinities that computed as NaN + iNaN. */ - _Bool recalc = 0; - if (isinf (a) || isinf (b)) - { - /* z is infinite. "Box" the infinity and change NaNs in - the other factor to 0. */ - a = COPYSIGN (isinf (a) ? 1 : 0, a); - b = COPYSIGN (isinf (b) ? 1 : 0, b); - if (isnan (c)) c = COPYSIGN (0, c); - if (isnan (d)) d = COPYSIGN (0, d); - recalc = 1; - } - if (isinf (c) || isinf (d)) - { - /* w is infinite. "Box" the infinity and change NaNs in - the other factor to 0. */ - c = COPYSIGN (isinf (c) ? 1 : 0, c); - d = COPYSIGN (isinf (d) ? 1 : 0, d); - if (isnan (a)) a = COPYSIGN (0, a); - if (isnan (b)) b = COPYSIGN (0, b); - recalc = 1; - } - if (!recalc - && (isinf (ac) || isinf (bd) - || isinf (ad) || isinf (bc))) - { - /* Recover infinities from overflow by changing NaNs to 0. */ - if (isnan (a)) a = COPYSIGN (0, a); - if (isnan (b)) b = COPYSIGN (0, b); - if (isnan (c)) c = COPYSIGN (0, c); - if (isnan (d)) d = COPYSIGN (0, d); - recalc = 1; - } - if (recalc) - { - x = INFINITY * (a * c - b * d); - y = INFINITY * (a * d + b * c); - } - } - - return x + I * y; -} -#endif /* complex multiply */ - -#if defined(L_divsc3) || defined(L_divdc3) \ - || defined(L_divxc3) || defined(L_divtc3) - -CTYPE -CONCAT3(__div,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d) -{ - MTYPE denom, ratio, x, y; - - /* ??? We can get better behavior from logarithmic scaling instead of - the division. But that would mean starting to link libgcc against - libm. We could implement something akin to ldexp/frexp as gcc builtins - fairly easily... */ - if (FABS (c) < FABS (d)) - { - ratio = c / d; - denom = (c * ratio) + d; - x = ((a * ratio) + b) / denom; - y = ((b * ratio) - a) / denom; - } - else - { - ratio = d / c; - denom = (d * ratio) + c; - x = ((b * ratio) + a) / denom; - y = (b - (a * ratio)) / denom; - } - - /* Recover infinities and zeros that computed as NaN+iNaN; the only cases - are nonzero/zero, infinite/finite, and finite/infinite. */ - if (isnan (x) && isnan (y)) - { - if (c == 0.0 && d == 0.0 && (!isnan (a) || !isnan (b))) - { - x = COPYSIGN (INFINITY, c) * a; - y = COPYSIGN (INFINITY, c) * b; - } - else if ((isinf (a) || isinf (b)) && isfinite (c) && isfinite (d)) - { - a = COPYSIGN (isinf (a) ? 1 : 0, a); - b = COPYSIGN (isinf (b) ? 1 : 0, b); - x = INFINITY * (a * c + b * d); - y = INFINITY * (b * c - a * d); - } - else if ((isinf (c) || isinf (d)) && isfinite (a) && isfinite (b)) - { - c = COPYSIGN (isinf (c) ? 1 : 0, c); - d = COPYSIGN (isinf (d) ? 1 : 0, d); - x = 0.0 * (a * c + b * d); - y = 0.0 * (b * c - a * d); - } - } - - return x + I * y; -} -#endif /* complex divide */ - -#endif /* all complex float routines */ - /* From here on down, the routines use normal data types. */ #define SItype bogus_type @@ -2012,7 +1575,7 @@ __enable_execute_stack (void *addr __attribute__((__unused__))) #if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN) -int +long getpagesize (void) { #ifdef _ALPHA_ @@ -2061,7 +1624,6 @@ TRANSFER_FROM_TRAMPOLINE #ifdef L__main #include "gbl-ctors.h" - /* Some systems use __main in a way incompatible with its use in gcc, in these cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to give the same symbol without quotes for an alternative entry point. You @@ -2071,7 +1633,7 @@ TRANSFER_FROM_TRAMPOLINE #define SYMBOL__MAIN __main #endif -#if defined (INIT_SECTION_ASM_OP) || defined (INIT_ARRAY_SECTION_ASM_OP) +#ifdef INIT_SECTION_ASM_OP #undef HAS_INIT_SECTION #define HAS_INIT_SECTION #endif @@ -2184,4 +1746,4 @@ func_ptr __DTOR_LIST__[2]; #endif #endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */ #endif /* L_ctors */ -#endif /* LIBGCC2_UNITS_PER_WORD <= MIN_UNITS_PER_WORD */ + diff --git a/contrib/gcc/make-temp-file.c b/contrib/gcc/make-temp-file.c index 8833504..563bd46 100644 --- a/contrib/gcc/make-temp-file.c +++ b/contrib/gcc/make-temp-file.c @@ -17,6 +17,8 @@ License along with libiberty; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $FreeBSD$ */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -112,10 +114,10 @@ choose_tmpdir () base = try (P_tmpdir, base); #endif - /* Try /var/tmp, /usr/tmp, then /tmp. */ + /* Try /tmp, /var/tmp, then /usr/tmp. */ + base = try (tmp, base); base = try (vartmp, base); base = try (usrtmp, base); - base = try (tmp, base); /* If all else fails, use the current directory! */ if (base == 0) diff --git a/contrib/gcc/opts.c b/contrib/gcc/opts.c index 3c2abad..4fbec28 100644 --- a/contrib/gcc/opts.c +++ b/contrib/gcc/opts.c @@ -1,6 +1,5 @@ /* Command line option handling. - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Neil Booth. This file is part of GCC. @@ -17,8 +16,10 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* $FreeBSD$ */ #include "config.h" #include "system.h" @@ -38,8 +39,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "diagnostic.h" #include "tm_p.h" /* For OPTIMIZATION_OPTIONS. */ #include "insn-attr.h" /* For INSN_SCHEDULING. */ -#include "target.h" -#include "tree-pass.h" /* Value of the -G xx switch, and whether it was passed or not. */ unsigned HOST_WIDE_INT g_switch_value; @@ -48,22 +47,85 @@ bool g_switch_set; /* True if we should exit after parsing options. */ bool exit_after_options; +/* If -version. */ +bool version_flag; + /* Print various extra warnings. -W/-Wextra. */ bool extra_warnings; +/* Don't print warning messages. -w. */ +bool inhibit_warnings; + +/* Treat warnings as errors. -Werror. */ +bool warnings_are_errors; + +/* Warn if a function returns an aggregate, since there are often + incompatible calling conventions for doing this. */ +bool warn_aggregate_return; + +/* Nonzero means warn about pointer casts that increase the required + alignment of the target type (and might therefore lead to a crash + due to a misaligned access). */ +bool warn_cast_align; + +/* Nonzero means warn about uses of __attribute__((deprecated)) + declarations. */ +bool warn_deprecated_decl = true; + +/* Warn when an optimization pass is disabled. */ +bool warn_disabled_optimization; + +/* Nonzero means warn if inline function is too large. */ +bool warn_inline; + /* True to warn about any objects definitions whose size is larger than N bytes. Also want about function definitions whose returned values are larger than N bytes, where N is `larger_than_size'. */ bool warn_larger_than; HOST_WIDE_INT larger_than_size; +/* Warn about functions which might be candidates for attribute noreturn. */ +bool warn_missing_noreturn; + +/* True to warn about code which is never reached. */ +bool warn_notreached; + +/* Warn if packed attribute on struct is unnecessary and inefficient. */ +bool warn_packed; + +/* Warn when gcc pads a structure to an alignment boundary. */ +bool warn_padded; + +/* True means warn about all declarations which shadow others. */ +bool warn_shadow; + /* Nonzero means warn about constructs which might not be strict-aliasing safe. */ -int warn_strict_aliasing; +bool warn_strict_aliasing; -/* Nonzero means warn about optimizations which rely on undefined - signed overflow. */ -int warn_strict_overflow; +/* True to warn if a switch on an enum, that does not have a default + case, fails to have a case for every enum value. */ +bool warn_switch; + +/* Warn if a switch does not have a default case. */ +bool warn_switch_default; + +/* Warn if a switch on an enum fails to have a case for every enum + value (regardless of the presence or otherwise of a default case). */ +bool warn_switch_enum; + +/* Don't suppress warnings from system headers. -Wsystem-headers. */ +bool warn_system_headers; + +/* True to warn about variables used before they are initialized. */ +int warn_uninitialized; + +/* True to warn about unused variables, functions et.al. */ +bool warn_unused_function; +bool warn_unused_label; +bool warn_unused_parameter; +bool warn_unused_variable; +bool warn_unused_value; /* Hack for cooperation between set_Wunused and set_Wextra. */ static bool maybe_warn_unused_parameter; @@ -82,17 +144,6 @@ enum debug_info_level debug_info_level = DINFO_LEVEL_NONE; write_symbols is set to DBX_DEBUG, XCOFF_DEBUG, or DWARF_DEBUG. */ bool use_gnu_debug_info_extensions; -/* The default visibility for all symbols (unless overridden) */ -enum symbol_visibility default_visibility = VISIBILITY_DEFAULT; - -/* Disable unit-at-a-time for frontends that might be still broken in this - respect. */ - -bool no_unit_at_a_time_default; - -/* Global visibility options. */ -struct visibility_flags visibility_options; - /* Columns of --help display. */ static unsigned int columns = 80; @@ -110,8 +161,8 @@ static bool flag_peel_loops_set, flag_branch_probabilities_set; const char **in_fnames; unsigned num_in_fnames; -static int common_handle_option (size_t scode, const char *arg, int value, - unsigned int lang_mask); +static size_t find_opt (const char *, int); +static int common_handle_option (size_t scode, const char *arg, int value); static void handle_param (const char *); static void set_Wextra (int); static unsigned int handle_option (const char **argv, unsigned int lang_mask); @@ -120,14 +171,97 @@ static void complain_wrong_lang (const char *, const struct cl_option *, unsigned int lang_mask); static void handle_options (unsigned int, const char **, unsigned int); static void wrap_help (const char *help, const char *item, unsigned int); -static void print_target_help (void); static void print_help (void); static void print_param_help (void); -static void print_filtered_help (unsigned int); +static void print_filtered_help (unsigned int flag); static unsigned int print_switch (const char *text, unsigned int indent); static void set_debug_level (enum debug_info_type type, int extended, const char *arg); +/* Perform a binary search to find which option the command-line INPUT + matches. Returns its index in the option array, and N_OPTS + (cl_options_count) on failure. + + This routine is quite subtle. A normal binary search is not good + enough because some options can be suffixed with an argument, and + multiple sub-matches can occur, e.g. input of "-pedantic" matching + the initial substring of "-pedantic-errors". + + A more complicated example is -gstabs. It should match "-g" with + an argument of "stabs". Suppose, however, that the number and list + of switches are such that the binary search tests "-gen-decls" + before having tested "-g". This doesn't match, and as "-gen-decls" + is less than "-gstabs", it will become the lower bound of the + binary search range, and "-g" will never be seen. To resolve this + issue, opts.sh makes "-gen-decls" point, via the back_chain member, + to "-g" so that failed searches that end between "-gen-decls" and + the lexicographically subsequent switch know to go back and see if + "-g" causes a match (which it does in this example). + + This search is done in such a way that the longest match for the + front end in question wins. If there is no match for the current + front end, the longest match for a different front end is returned + (or N_OPTS if none) and the caller emits an error message. */ +static size_t +find_opt (const char *input, int lang_mask) +{ + size_t mn, mx, md, opt_len; + size_t match_wrong_lang; + int comp; + + mn = 0; + mx = cl_options_count; + + /* Find mn such this lexicographical inequality holds: + cl_options[mn] <= input < cl_options[mn + 1]. */ + while (mx - mn > 1) + { + md = (mn + mx) / 2; + opt_len = cl_options[md].opt_len; + comp = strncmp (input, cl_options[md].opt_text + 1, opt_len); + + if (comp < 0) + mx = md; + else + mn = md; + } + + /* This is the switch that is the best match but for a different + front end, or cl_options_count if there is no match at all. */ + match_wrong_lang = cl_options_count; + + /* Backtrace the chain of possible matches, returning the longest + one, if any, that fits best. With current GCC switches, this + loop executes at most twice. */ + do + { + const struct cl_option *opt = &cl_options[mn]; + + /* Is this switch a prefix of the input? */ + if (!strncmp (input, opt->opt_text + 1, opt->opt_len)) + { + /* If language is OK, and the match is exact or the switch + takes a joined argument, return it. */ + if ((opt->flags & lang_mask) + && (input[opt->opt_len] == '\0' || (opt->flags & CL_JOINED))) + return mn; + + /* If we haven't remembered a prior match, remember this + one. Any prior match is necessarily better. */ + if (match_wrong_lang == cl_options_count) + match_wrong_lang = mn; + } + + /* Try the next possibility. This is cl_options_count if there + are no more. */ + mn = opt->back_chain; + } + while (mn != cl_options_count); + + /* Return the best wrong match, or cl_options_count if none. */ + return match_wrong_lang; +} + /* If ARG is a non-negative integer made up solely of digits, return its value, otherwise return -1. */ static int @@ -156,7 +290,7 @@ write_langs (unsigned int mask) if (mask & (1U << n)) len += strlen (lang_name) + 1; - result = XNEWVEC (char, len); + result = xmalloc (len); len = 0; for (n = 0; (lang_name = lang_names[n]) != 0; n++) if (mask & (1U << n)) @@ -183,7 +317,7 @@ complain_wrong_lang (const char *text, const struct cl_option *option, bad_lang = write_langs (lang_mask); /* Eventually this should become a hard error IMO. */ - warning (0, "command line option \"%s\" is valid for %s but not for %s", + warning ("command line option \"%s\" is valid for %s but not for %s", text, ok_langs, bad_lang); free (ok_langs); @@ -204,23 +338,21 @@ handle_option (const char **argv, unsigned int lang_mask) opt = argv[0]; - opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET); - if (opt_index == cl_options_count - && (opt[1] == 'W' || opt[1] == 'f' || opt[1] == 'm') + /* Drop the "no-" from negative switches. */ + if ((opt[1] == 'W' || opt[1] == 'f') && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-') { - /* Drop the "no-" from negative switches. */ size_t len = strlen (opt) - 3; - dup = XNEWVEC (char, len + 1); + dup = xmalloc (len + 1); dup[0] = '-'; dup[1] = opt[1]; memcpy (dup + 2, opt + 5, len - 2 + 1); opt = dup; value = 0; - opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET); } + opt_index = find_opt (opt + 1, lang_mask | CL_COMMON); if (opt_index == cl_options_count) goto done; @@ -234,14 +366,6 @@ handle_option (const char **argv, unsigned int lang_mask) /* We've recognized this switch. */ result = 1; - /* Check to see if the option is disabled for this configuration. */ - if (option->flags & CL_DISABLED) - { - error ("command line option %qs" - " is not supported by this configuration", opt); - goto done; - } - /* Sort out any argument the switch takes. */ if (option->flags & CL_JOINED) { @@ -272,7 +396,7 @@ handle_option (const char **argv, unsigned int lang_mask) /* Now we've swallowed any potential argument, complain if this is a switch for a different front end. */ - if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET))) + if (!(option->flags & (lang_mask | CL_COMMON))) { complain_wrong_lang (argv[0], option, lang_mask); goto done; @@ -280,7 +404,7 @@ handle_option (const char **argv, unsigned int lang_mask) if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE))) { - if (!lang_hooks.missing_argument (opt, opt_index)) + if (!(*lang_hooks.missing_argument) (opt, opt_index)) error ("missing argument to \"%s\"", opt); goto done; } @@ -297,44 +421,12 @@ handle_option (const char **argv, unsigned int lang_mask) } } - if (option->flag_var) - switch (option->var_type) - { - case CLVC_BOOLEAN: - *(int *) option->flag_var = value; - break; - - case CLVC_EQUAL: - *(int *) option->flag_var = (value - ? option->var_value - : !option->var_value); - break; - - case CLVC_BIT_CLEAR: - case CLVC_BIT_SET: - if ((value != 0) == (option->var_type == CLVC_BIT_SET)) - *(int *) option->flag_var |= option->var_value; - else - *(int *) option->flag_var &= ~option->var_value; - if (option->flag_var == &target_flags) - target_flags_explicit |= option->var_value; - break; - - case CLVC_STRING: - *(const char **) option->flag_var = arg; - break; - } - if (option->flags & lang_mask) - if (lang_hooks.handle_option (opt_index, arg, value) == 0) + if ((*lang_hooks.handle_option) (opt_index, arg, value) == 0) result = 0; if (result && (option->flags & CL_COMMON)) - if (common_handle_option (opt_index, arg, value, lang_mask) == 0) - result = 0; - - if (result && (option->flags & CL_TARGET)) - if (!targetm.handle_option (opt_index, arg, value)) + if (common_handle_option (opt_index, arg, value) == 0) result = 0; done: @@ -343,15 +435,6 @@ handle_option (const char **argv, unsigned int lang_mask) return result; } -/* Handle FILENAME from the command line. */ -static void -add_input_filename (const char *filename) -{ - num_in_fnames++; - in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0])); - in_fnames[num_in_fnames - 1] = filename; -} - /* Decode and handle the vector of command line options. LANG_MASK contains has a single bit set representing the current language. */ @@ -384,6 +467,15 @@ handle_options (unsigned int argc, const char **argv, unsigned int lang_mask) } } +/* Handle FILENAME from the command line. */ +void +add_input_filename (const char *filename) +{ + num_in_fnames++; + in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0])); + in_fnames[num_in_fnames - 1] = filename; +} + /* Parse command line options and set default flag values. Do minimal options processing. */ void @@ -392,7 +484,7 @@ decode_options (unsigned int argc, const char **argv) unsigned int i, lang_mask; /* Perform language-specific options initialization. */ - lang_mask = lang_hooks.init_options (argc, argv); + lang_mask = (*lang_hooks.init_options) (argc, argv); lang_hooks.initialize_diagnostics (global_dc); @@ -437,6 +529,7 @@ decode_options (unsigned int argc, const char **argv) if (optimize >= 1) { flag_defer_pop = 1; + flag_thread_jumps = 1; #ifdef DELAY_SLOTS flag_delayed_branch = 1; #endif @@ -445,47 +538,24 @@ decode_options (unsigned int argc, const char **argv) #endif flag_guess_branch_prob = 1; flag_cprop_registers = 1; + flag_loop_optimize = 1; flag_if_conversion = 1; flag_if_conversion2 = 1; - flag_ipa_pure_const = 1; - flag_ipa_reference = 1; - flag_tree_ccp = 1; - flag_tree_dce = 1; - flag_tree_dom = 1; - flag_tree_dse = 1; - flag_tree_ter = 1; - flag_tree_live_range_split = 1; - flag_tree_sra = 1; - flag_tree_copyrename = 1; - flag_tree_fre = 1; - flag_tree_copy_prop = 1; - flag_tree_sink = 1; - flag_tree_salias = 1; - if (!no_unit_at_a_time_default) - flag_unit_at_a_time = 1; - - if (!optimize_size) - { - /* Loop header copying usually increases size of the code. This used - not to be true, since quite often it is possible to verify that - the condition is satisfied in the first iteration and therefore - to eliminate it. Jump threading handles these cases now. */ - flag_tree_ch = 1; - } } if (optimize >= 2) { - flag_thread_jumps = 1; flag_crossjumping = 1; flag_optimize_sibling_calls = 1; flag_cse_follow_jumps = 1; flag_cse_skip_blocks = 1; flag_gcse = 1; flag_expensive_optimizations = 1; - flag_ipa_type_escape = 1; + flag_strength_reduce = 1; flag_rerun_cse_after_loop = 1; + flag_rerun_loop_opt = 1; flag_caller_saves = 1; + flag_force_mem = 1; flag_peephole2 = 1; #ifdef INSN_SCHEDULING flag_schedule_insns = 1; @@ -493,29 +563,21 @@ decode_options (unsigned int argc, const char **argv) #endif flag_regmove = 1; flag_strict_aliasing = 1; - flag_strict_overflow = 1; flag_delete_null_pointer_checks = 1; flag_reorder_blocks = 1; flag_reorder_functions = 1; - flag_tree_store_ccp = 1; - flag_tree_store_copy_prop = 1; - flag_tree_vrp = 1; - - if (!optimize_size) - { - /* PRE tends to generate bigger code. */ - flag_tree_pre = 1; - } + flag_unit_at_a_time = 1; } if (optimize >= 3) { flag_inline_functions = 1; + flag_rename_registers = 1; flag_unswitch_loops = 1; - flag_gcse_after_reload = 1; + flag_web = 1; } - if (optimize < 2 || optimize_size) + if (optimize_size) { align_loops = 1; align_jumps = 1; @@ -530,32 +592,25 @@ decode_options (unsigned int argc, const char **argv) or less automatically remove extra jumps, but would also try to use more short jumps instead of long jumps. */ flag_reorder_blocks = 0; - flag_reorder_blocks_and_partition = 0; - } - - if (optimize_size) - { - /* Inlining of very small functions usually reduces total size. */ - set_param_value ("max-inline-insns-single", 5); - set_param_value ("max-inline-insns-auto", 5); - flag_inline_functions = 1; - - /* We want to crossjump as much as possible. */ - set_param_value ("min-crossjump-insns", 1); } /* Initialize whether `char' is signed. */ flag_signed_char = DEFAULT_SIGNED_CHAR; - /* Set this to a special "uninitialized" value. The actual default is set - after target options have been processed. */ - flag_short_enums = 2; +#ifdef DEFAULT_SHORT_ENUMS + /* Initialize how much space enums occupy, by default. */ + flag_short_enums = DEFAULT_SHORT_ENUMS; +#endif /* Initialize target_flags before OPTIMIZATION_OPTIONS so the latter can modify it. */ - target_flags = targetm.default_target_flags; + target_flags = 0; + set_target_switch (""); - /* Some tagets have ABI-specified unwind tables. */ - flag_unwind_tables = targetm.unwind_tables_default; + /* Unwind tables are always present in an ABI-conformant IA-64 + object file, so the default should be ON. */ +#ifdef IA64_UNWIND_INFO + flag_unwind_tables = IA64_UNWIND_INFO; +#endif #ifdef OPTIMIZATION_OPTIONS /* Allow default optimizations to be specified on a per-machine basis. */ @@ -590,66 +645,26 @@ decode_options (unsigned int argc, const char **argv) this to `2' if -Wall is used, so we can avoid giving out lots of errors for people who don't realize what -Wall does. */ if (warn_uninitialized == 1) - warning (OPT_Wuninitialized, - "-Wuninitialized is not supported without -O"); + warning ("-Wuninitialized is not supported without -O"); } if (flag_really_no_inline == 2) flag_really_no_inline = flag_no_inline; - - /* The optimization to partition hot and cold basic blocks into separate - sections of the .o and executable files does not work (currently) - with exception handling. This is because there is no support for - generating unwind info. If flag_exceptions is turned on we need to - turn off the partitioning optimization. */ - - if (flag_exceptions && flag_reorder_blocks_and_partition) - { - inform - ("-freorder-blocks-and-partition does not work with exceptions"); - flag_reorder_blocks_and_partition = 0; - flag_reorder_blocks = 1; - } - - /* If user requested unwind info, then turn off the partitioning - optimization. */ - - if (flag_unwind_tables && ! targetm.unwind_tables_default - && flag_reorder_blocks_and_partition) - { - inform ("-freorder-blocks-and-partition does not support unwind info"); - flag_reorder_blocks_and_partition = 0; - flag_reorder_blocks = 1; - } - - /* If the target requested unwind info, then turn off the partitioning - optimization with a different message. Likewise, if the target does not - support named sections. */ - - if (flag_reorder_blocks_and_partition - && (!targetm.have_named_sections - || (flag_unwind_tables && targetm.unwind_tables_default))) - { - inform - ("-freorder-blocks-and-partition does not work on this architecture"); - flag_reorder_blocks_and_partition = 0; - flag_reorder_blocks = 1; - } } /* Handle target- and language-independent options. Return zero to - generate an "unknown option" message. Only options that need - extra handling need to be listed here; if you simply want - VALUE assigned to a variable, it happens automatically. */ - + generate an "unknown option" message. */ static int -common_handle_option (size_t scode, const char *arg, int value, - unsigned int lang_mask) +common_handle_option (size_t scode, const char *arg, + int value ATTRIBUTE_UNUSED) { enum opt_code code = (enum opt_code) scode; switch (code) { + default: + abort (); + case OPT__help: print_help (); exit_after_options = true; @@ -660,7 +675,7 @@ common_handle_option (size_t scode, const char *arg, int value, break; case OPT__target_help: - print_target_help (); + display_target_options (); exit_after_options = true; break; @@ -684,61 +699,107 @@ common_handle_option (size_t scode, const char *arg, int value, set_Wextra (value); break; - case OPT_Werror_: - { - char *new_option; - int option_index; - new_option = XNEWVEC (char, strlen (arg) + 2); - new_option[0] = 'W'; - strcpy (new_option+1, arg); - option_index = find_opt (new_option, lang_mask); - if (option_index == N_OPTS) - { - error ("-Werror=%s: No option -%s", arg, new_option); - } - else - { - int kind = value ? DK_ERROR : DK_WARNING; - diagnostic_classify_diagnostic (global_dc, option_index, kind); - - /* -Werror=foo implies -Wfoo. */ - if (cl_options[option_index].var_type == CLVC_BOOLEAN - && cl_options[option_index].flag_var - && kind == DK_ERROR) - *(int *) cl_options[option_index].flag_var = 1; - free (new_option); - } - } + case OPT_Waggregate_return: + warn_aggregate_return = value; + break; + + case OPT_Wcast_align: + warn_cast_align = value; + break; + + case OPT_Wdeprecated_declarations: + warn_deprecated_decl = value; + break; + + case OPT_Wdisabled_optimization: + warn_disabled_optimization = value; + break; + + case OPT_Werror: + warnings_are_errors = value; break; case OPT_Wextra: set_Wextra (value); break; + case OPT_Winline: + warn_inline = value; + break; + case OPT_Wlarger_than_: larger_than_size = value; warn_larger_than = value != -1; break; + case OPT_Wmissing_noreturn: + warn_missing_noreturn = value; + break; + + case OPT_Wpacked: + warn_packed = value; + break; + + case OPT_Wpadded: + warn_padded = value; + break; + + case OPT_Wshadow: + warn_shadow = value; + break; + case OPT_Wstrict_aliasing: - case OPT_Wstrict_aliasing_: warn_strict_aliasing = value; break; - case OPT_Wstrict_overflow: - warn_strict_overflow = (value - ? (int) WARN_STRICT_OVERFLOW_CONDITIONAL - : 0); + case OPT_Wswitch: + warn_switch = value; + break; + + case OPT_Wswitch_default: + warn_switch_default = value; + break; + + case OPT_Wswitch_enum: + warn_switch_enum = value; + break; + + case OPT_Wsystem_headers: + warn_system_headers = value; + break; + + case OPT_Wuninitialized: + warn_uninitialized = value; break; - case OPT_Wstrict_overflow_: - warn_strict_overflow = value; + case OPT_Wunreachable_code: + warn_notreached = value; break; case OPT_Wunused: set_Wunused (value); break; + case OPT_Wunused_function: + warn_unused_function = value; + break; + + case OPT_Wunused_label: + warn_unused_label = value; + break; + + case OPT_Wunused_parameter: + warn_unused_parameter = value; + break; + + case OPT_Wunused_value: + warn_unused_value = value; + break; + + case OPT_Wunused_variable: + warn_unused_variable = value; + break; + case OPT_aux_info: case OPT_aux_info_: aux_info_file_name = arg; @@ -766,24 +827,85 @@ common_handle_option (size_t scode, const char *arg, int value, dump_base_name = arg; break; + case OPT_fPIC: + flag_pic = value + value; + break; + + case OPT_fPIE: + flag_pie = value + value; + break; + + case OPT_fabi_version_: + flag_abi_version = value; + break; + + case OPT_falign_functions: + align_functions = !value; + break; + case OPT_falign_functions_: align_functions = value; break; + case OPT_falign_jumps: + align_jumps = !value; + break; + case OPT_falign_jumps_: align_jumps = value; break; + case OPT_falign_labels: + align_labels = !value; + break; + case OPT_falign_labels_: align_labels = value; break; + case OPT_falign_loops: + align_loops = !value; + break; + case OPT_falign_loops_: align_loops = value; break; + case OPT_fargument_alias: + flag_argument_noalias = !value; + break; + + case OPT_fargument_noalias: + flag_argument_noalias = value; + break; + + case OPT_fargument_noalias_global: + flag_argument_noalias = value + value; + break; + + case OPT_fasynchronous_unwind_tables: + flag_asynchronous_unwind_tables = value; + break; + + case OPT_fbounds_check: + flag_bounds_check = value; + break; + + case OPT_fbranch_count_reg: + flag_branch_on_count_reg = value; + break; + case OPT_fbranch_probabilities: flag_branch_probabilities_set = true; + flag_branch_probabilities = value; + break; + + case OPT_fbranch_target_load_optimize: + flag_branch_target_load_optimize = value; + break; + + case OPT_fbranch_target_load_optimize2: + flag_branch_target_load_optimize2 = value; break; case OPT_fcall_used_: @@ -794,6 +916,46 @@ common_handle_option (size_t scode, const char *arg, int value, fix_register (arg, 0, 0); break; + case OPT_fcaller_saves: + flag_caller_saves = value; + break; + + case OPT_fcommon: + flag_no_common = !value; + break; + + case OPT_fcprop_registers: + flag_cprop_registers = value; + break; + + case OPT_fcrossjumping: + flag_crossjumping = value; + break; + + case OPT_fcse_follow_jumps: + flag_cse_follow_jumps = value; + break; + + case OPT_fcse_skip_blocks: + flag_cse_skip_blocks = value; + break; + + case OPT_fdata_sections: + flag_data_sections = value; + break; + + case OPT_fdefer_pop: + flag_defer_pop = value; + break; + + case OPT_fdelayed_branch: + flag_delayed_branch = value; + break; + + case OPT_fdelete_null_pointer_checks: + flag_delete_null_pointer_checks = value; + break; + case OPT_fdiagnostics_show_location_: if (!strcmp (arg, "once")) diagnostic_prefixing_rule (global_dc) = DIAGNOSTICS_SHOW_PREFIX_ONCE; @@ -804,49 +966,225 @@ common_handle_option (size_t scode, const char *arg, int value, return 0; break; - case OPT_fdiagnostics_show_option: - global_dc->show_option_requested = true; + case OPT_fdump_unnumbered: + flag_dump_unnumbered = value; break; - case OPT_fdump_: - if (!dump_switch_p (arg)) - return 0; + case OPT_feliminate_dwarf2_dups: + flag_eliminate_dwarf2_dups = value; + break; + + case OPT_feliminate_unused_debug_types: + flag_eliminate_unused_debug_types = value; + break; + + case OPT_feliminate_unused_debug_symbols: + flag_debug_only_used_symbols = value; + break; + + case OPT_fexceptions: + flag_exceptions = value; + break; + + case OPT_fexpensive_optimizations: + flag_expensive_optimizations = value; break; case OPT_ffast_math: set_fast_math_flags (value); break; + case OPT_ffinite_math_only: + flag_finite_math_only = value; + break; + case OPT_ffixed_: fix_register (arg, 1, 1); break; + case OPT_ffunction_cse: + flag_no_function_cse = !value; + break; + + case OPT_ffloat_store: + flag_float_store = value; + break; + + case OPT_fforce_addr: + flag_force_addr = value; + break; + + case OPT_fforce_mem: + flag_force_mem = value; + break; + + case OPT_ffunction_sections: + flag_function_sections = value; + break; + + case OPT_fgcse: + flag_gcse = value; + break; + + case OPT_fgcse_lm: + flag_gcse_lm = value; + break; + + case OPT_fgcse_sm: + flag_gcse_sm = value; + break; + + case OPT_fgcse_las: + flag_gcse_las = value; + break; + + case OPT_fguess_branch_probability: + flag_guess_branch_prob = value; + break; + + case OPT_fident: + flag_no_ident = !value; + break; + + case OPT_fif_conversion: + flag_if_conversion = value; + break; + + case OPT_fif_conversion2: + flag_if_conversion2 = value; + break; + + case OPT_finhibit_size_directive: + flag_inhibit_size_directive = value; + break; + + case OPT_finline: + flag_no_inline = !value; + break; + + case OPT_finline_functions: + flag_inline_functions = value; + break; + case OPT_finline_limit_: case OPT_finline_limit_eq: set_param_value ("max-inline-insns-single", value / 2); set_param_value ("max-inline-insns-auto", value / 2); + set_param_value ("max-inline-insns-rtl", value); + break; + + case OPT_finstrument_functions: + flag_instrument_function_entry_exit = value; + break; + + case OPT_fkeep_inline_functions: + flag_keep_inline_functions =value; + break; + + case OPT_fkeep_static_consts: + flag_keep_static_consts = value; + break; + + case OPT_fleading_underscore: + flag_leading_underscore = value; + break; + + case OPT_floop_optimize: + flag_loop_optimize = value; + break; + + case OPT_fmath_errno: + flag_errno_math = value; + break; + + case OPT_fmem_report: + mem_report = value; + break; + + case OPT_fmerge_all_constants: + flag_merge_constants = value + value; + break; + + case OPT_fmerge_constants: + flag_merge_constants = value; break; case OPT_fmessage_length_: pp_set_line_maximum_length (global_dc->printer, value); break; - case OPT_fpack_struct_: - if (value <= 0 || (value & (value - 1)) || value > 16) - error("structure alignment must be a small power of two, not %d", value); - else - { - initial_max_fld_align = value; - maximum_field_alignment = value * BITS_PER_UNIT; - } + case OPT_fmove_all_movables: + flag_move_all_movables = value; + break; + + case OPT_fnew_ra: + flag_new_regalloc = value; + break; + + case OPT_fnon_call_exceptions: + flag_non_call_exceptions = value; + break; + + case OPT_fold_unroll_all_loops: + flag_old_unroll_all_loops = value; + break; + + case OPT_fold_unroll_loops: + flag_old_unroll_loops = value; + break; + + case OPT_fomit_frame_pointer: + flag_omit_frame_pointer = value; + break; + + case OPT_foptimize_register_move: + flag_regmove = value; + break; + + case OPT_foptimize_sibling_calls: + flag_optimize_sibling_calls = value; + break; + + case OPT_fpack_struct: + flag_pack_struct = value; break; case OPT_fpeel_loops: flag_peel_loops_set = true; + flag_peel_loops = value; + break; + + case OPT_fpcc_struct_return: + flag_pcc_struct_return = value; + break; + + case OPT_fpeephole: + flag_no_peephole = !value; + break; + + case OPT_fpeephole2: + flag_peephole2 = value; + break; + + case OPT_fpic: + flag_pic = value; + break; + + case OPT_fpie: + flag_pie = value; + break; + + case OPT_fprefetch_loop_arrays: + flag_prefetch_loop_arrays = value; + break; + + case OPT_fprofile: + profile_flag = value; break; case OPT_fprofile_arcs: profile_arc_flag_set = true; + profile_arc_flag = value; break; case OPT_fprofile_use: @@ -875,25 +1213,12 @@ common_handle_option (size_t scode, const char *arg, int value, case OPT_fprofile_values: flag_profile_values_set = true; - break; - - case OPT_fvisibility_: - { - if (!strcmp(arg, "default")) - default_visibility = VISIBILITY_DEFAULT; - else if (!strcmp(arg, "internal")) - default_visibility = VISIBILITY_INTERNAL; - else if (!strcmp(arg, "hidden")) - default_visibility = VISIBILITY_HIDDEN; - else if (!strcmp(arg, "protected")) - default_visibility = VISIBILITY_PROTECTED; - else - error ("unrecognized visibility value \"%s\"", arg); - } + flag_profile_values = value; break; case OPT_fvpt: - flag_value_profile_transformations_set = true; + flag_value_profile_transformations_set = value; + flag_value_profile_transformations = value; break; case OPT_frandom_seed: @@ -907,6 +1232,58 @@ common_handle_option (size_t scode, const char *arg, int value, flag_random_seed = arg; break; + case OPT_freduce_all_givs: + flag_reduce_all_givs = value; + break; + + case OPT_freg_struct_return: + flag_pcc_struct_return = !value; + break; + + case OPT_fregmove: + flag_regmove = value; + break; + + case OPT_frename_registers: + flag_rename_registers = value; + break; + + case OPT_freorder_blocks: + flag_reorder_blocks = value; + break; + + case OPT_freorder_functions: + flag_reorder_functions = value; + break; + + case OPT_frerun_cse_after_loop: + flag_rerun_cse_after_loop = value; + break; + + case OPT_frerun_loop_opt: + flag_rerun_loop_opt = value; + break; + + case OPT_frounding_math: + flag_rounding_math = value; + break; + + case OPT_fsched_interblock: + flag_schedule_interblock = value; + break; + + case OPT_fsched_spec: + flag_schedule_speculative = value; + break; + + case OPT_fsched_spec_load: + flag_schedule_speculative_load = value; + break; + + case OPT_fsched_spec_load_dangerous: + flag_schedule_speculative_load_dangerous = value; + break; + case OPT_fsched_verbose_: #ifdef INSN_SCHEDULING fix_sched_param ("verbose", arg); @@ -915,16 +1292,56 @@ common_handle_option (size_t scode, const char *arg, int value, return 0; #endif + case OPT_fsched2_use_superblocks: + flag_sched2_use_superblocks = value; + break; + + case OPT_fsched2_use_traces: + flag_sched2_use_traces = value; + break; + + case OPT_fschedule_insns: + flag_schedule_insns = value; + break; + + case OPT_fschedule_insns2: + flag_schedule_insns_after_reload = value; + break; + + case OPT_fsched_stalled_insns: + flag_sched_stalled_insns = value; + break; + case OPT_fsched_stalled_insns_: flag_sched_stalled_insns = value; if (flag_sched_stalled_insns == 0) flag_sched_stalled_insns = -1; break; + case OPT_fsched_stalled_insns_dep: + flag_sched_stalled_insns_dep = 1; + break; + case OPT_fsched_stalled_insns_dep_: flag_sched_stalled_insns_dep = value; break; + case OPT_fshared_data: + flag_shared_data = value; + break; + + case OPT_fsignaling_nans: + flag_signaling_nans = value; + break; + + case OPT_fsingle_precision_constant: + flag_single_precision_constant = value; + break; + + case OPT_fstack_check: + flag_stack_check = value; + break; + case OPT_fstack_limit: /* The real switch is -fno-stack-limit. */ if (value) @@ -946,8 +1363,28 @@ common_handle_option (size_t scode, const char *arg, int value, stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (arg)); break; - case OPT_ftree_vectorizer_verbose_: - vect_set_verbosity_level (arg); + case OPT_fstrength_reduce: + flag_strength_reduce = value; + break; + + case OPT_fstrict_aliasing: + flag_strict_aliasing = value; + break; + + case OPT_fsyntax_only: + flag_syntax_only = value; + break; + + case OPT_ftest_coverage: + flag_test_coverage = value; + break; + + case OPT_fthread_jumps: + flag_thread_jumps = value; + break; + + case OPT_ftime_report: + time_report = value; break; case OPT_ftls_model_: @@ -960,15 +1397,68 @@ common_handle_option (size_t scode, const char *arg, int value, else if (!strcmp (arg, "local-exec")) flag_tls_default = TLS_MODEL_LOCAL_EXEC; else - warning (0, "unknown tls-model \"%s\"", arg); + warning ("unknown tls-model \"%s\"", arg); break; case OPT_ftracer: flag_tracer_set = true; + flag_tracer = value; + break; + + case OPT_ftrapping_math: + flag_trapping_math = value; + break; + + case OPT_ftrapv: + flag_trapv = value; + break; + + case OPT_funit_at_a_time: + flag_unit_at_a_time = value; + break; + + case OPT_funroll_all_loops: + flag_unroll_all_loops = value; break; case OPT_funroll_loops: flag_unroll_loops_set = true; + flag_unroll_loops = value; + break; + + case OPT_funsafe_math_optimizations: + flag_unsafe_math_optimizations = value; + break; + + case OPT_funswitch_loops: + flag_unswitch_loops = value; + break; + + case OPT_funwind_tables: + flag_unwind_tables = value; + break; + + case OPT_fverbose_asm: + flag_verbose_asm = value; + break; + + case OPT_fweb: + flag_web = value; + break; + + case OPT_fwrapv: + flag_wrapv = value; + break; + + case OPT_fwritable_strings: + flag_writable_strings = value; + if (flag_writable_strings) + inform ("-fwritable-strings is deprecated; " + "see documentation for details"); + break; + + case OPT_fzero_initialized_in_bss: + flag_zero_initialized_in_bss = value; break; case OPT_g: @@ -1001,29 +1491,37 @@ common_handle_option (size_t scode, const char *arg, int value, set_debug_level (XCOFF_DEBUG, code == OPT_gxcoff_, arg); break; + case OPT_m: + set_target_switch (arg); + break; + case OPT_o: asm_file_name = arg; break; + case OPT_p: + profile_flag = 1; + break; + + case OPT_pedantic: + pedantic = 1; + break; + case OPT_pedantic_errors: flag_pedantic_errors = pedantic = 1; break; - case OPT_fforce_mem: - warning (0, "-f[no-]force-mem is nop and option will be removed in 4.3"); + case OPT_quiet: + quiet_flag = 1; break; - case OPT_floop_optimize: - case OPT_frerun_loop_opt: - case OPT_fstrength_reduce: - /* These are no-ops, preserved for backward compatibility. */ + case OPT_version: + version_flag = 1; break; - default: - /* If the flag was handled in a standard way, assume the lack of - processing here is intentional. */ - gcc_assert (cl_options[scode].flag_var); - break; + case OPT_w: + inhibit_warnings = true; + break; } return 1; @@ -1044,7 +1542,7 @@ handle_param (const char *carg) { value = integral_argument (equal + 1); if (value == -1) - error ("invalid --param value %qs", equal + 1); + error ("invalid --param value `%s'", equal + 1); else { *equal = '\0'; @@ -1102,7 +1600,6 @@ set_fast_math_flags (int set) { flag_signaling_nans = 0; flag_rounding_math = 0; - flag_cx_limited_range = 1; } } @@ -1141,7 +1638,7 @@ set_debug_level (enum debug_info_type type, int extended, const char *arg) } if (write_symbols == NO_DEBUG) - warning (0, "target system does not support debug output"); + warning ("target system does not support debug output"); } } else @@ -1170,27 +1667,6 @@ set_debug_level (enum debug_info_type type, int extended, const char *arg) } } -/* Display help for target options. */ -static void -print_target_help (void) -{ - unsigned int i; - static bool displayed = false; - - /* Avoid double printing for --help --target-help. */ - if (displayed) - return; - - displayed = true; - for (i = 0; i < cl_options_count; i++) - if ((cl_options[i].flags & (CL_TARGET | CL_UNDOCUMENTED)) == CL_TARGET) - { - printf (_("\nTarget specific options:\n")); - print_filtered_help (CL_TARGET); - break; - } -} - /* Output --help text. */ static void print_help (void) @@ -1217,7 +1693,8 @@ print_help (void) lang_names[i]); print_filtered_help (1U << i); } - print_target_help (); + + display_target_options (); } /* Print the help for --param. */ @@ -1254,7 +1731,7 @@ print_filtered_help (unsigned int flag) const char *help, *opt, *tab; static char *printed; - if (flag == CL_COMMON || flag == CL_TARGET) + if (flag == CL_COMMON) { filter = flag; if (!printed) @@ -1401,65 +1878,3 @@ wrap_help (const char *help, const char *item, unsigned int item_width) } while (remaining); } - -/* Return 1 if OPTION is enabled, 0 if it is disabled, or -1 if it isn't - a simple on-off switch. */ - -int -option_enabled (int opt_idx) -{ - const struct cl_option *option = &(cl_options[opt_idx]); - if (option->flag_var) - switch (option->var_type) - { - case CLVC_BOOLEAN: - return *(int *) option->flag_var != 0; - - case CLVC_EQUAL: - return *(int *) option->flag_var == option->var_value; - - case CLVC_BIT_CLEAR: - return (*(int *) option->flag_var & option->var_value) == 0; - - case CLVC_BIT_SET: - return (*(int *) option->flag_var & option->var_value) != 0; - - case CLVC_STRING: - break; - } - return -1; -} - -/* Fill STATE with the current state of option OPTION. Return true if - there is some state to store. */ - -bool -get_option_state (int option, struct cl_option_state *state) -{ - if (cl_options[option].flag_var == 0) - return false; - - switch (cl_options[option].var_type) - { - case CLVC_BOOLEAN: - case CLVC_EQUAL: - state->data = cl_options[option].flag_var; - state->size = sizeof (int); - break; - - case CLVC_BIT_CLEAR: - case CLVC_BIT_SET: - state->ch = option_enabled (option); - state->data = &state->ch; - state->size = 1; - break; - - case CLVC_STRING: - state->data = *(const char **) cl_options[option].flag_var; - if (state->data == 0) - state->data = ""; - state->size = strlen (state->data) + 1; - break; - } - return true; -} diff --git a/contrib/gcc/pexecute.c b/contrib/gcc/pexecute.c new file mode 100644 index 0000000..0f232ca --- /dev/null +++ b/contrib/gcc/pexecute.c @@ -0,0 +1,794 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. + Copyright (C) 1996-2000 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* $FreeBSD$ */ + +/* This file exports two functions: pexecute and pwait. */ + +/* This file lives in at least two places: libiberty and gcc. + Don't change one without the other. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <errno.h> +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +#include "libiberty.h" +#include "safe-ctype.h" + +/* stdin file number. */ +#define STDIN_FILE_NO 0 + +/* stdout file number. */ +#define STDOUT_FILE_NO 1 + +/* value of `pipe': port index for reading. */ +#define READ_PORT 0 + +/* value of `pipe': port index for writing. */ +#define WRITE_PORT 1 + +static char *install_error_msg = "installation problem, cannot exec `%s'"; + +/* pexecute: execute a program. + +@deftypefn Extension int pexecute (const char *@var{program}, char * const *@var{argv}, const char *@var{this_pname}, const char *@var{temp_base}, char **@var{errmsg_fmt}, char **@var{errmsg_arg}, int flags) + +Executes a program. + +@var{program} and @var{argv} are the arguments to +@code{execv}/@code{execvp}. + +@var{this_pname} is name of the calling program (i.e., @code{argv[0]}). + +@var{temp_base} is the path name, sans suffix, of a temporary file to +use if needed. This is currently only needed for MS-DOS ports that +don't use @code{go32} (do any still exist?). Ports that don't need it +can pass @code{NULL}. + +(@code{@var{flags} & PEXECUTE_SEARCH}) is non-zero if @env{PATH} should be searched +(??? It's not clear that GCC passes this flag correctly). (@code{@var{flags} & +PEXECUTE_FIRST}) is nonzero for the first process in chain. +(@code{@var{flags} & PEXECUTE_FIRST}) is nonzero for the last process +in chain. The first/last flags could be simplified to only mark the +last of a chain of processes but that requires the caller to always +mark the last one (and not give up early if some error occurs). +It's more robust to require the caller to mark both ends of the chain. + +The result is the pid on systems like Unix where we +@code{fork}/@code{exec} and on systems like WIN32 and OS/2 where we +use @code{spawn}. It is up to the caller to wait for the child. + +The result is the @code{WEXITSTATUS} on systems like MS-DOS where we +@code{spawn} and wait for the child here. + +Upon failure, @var{errmsg_fmt} and @var{errmsg_arg} are set to the +text of the error message with an optional argument (if not needed, +@var{errmsg_arg} is set to @code{NULL}), and @minus{}1 is returned. +@code{errno} is available to the caller to use. + +@end deftypefn + +@deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags}) + +Waits for a program started by @code{pexecute} to finish. + +@var{pid} is the process id of the task to wait for. @var{status} is +the `status' argument to wait. @var{flags} is currently unused (allows +future enhancement without breaking upward compatibility). Pass 0 for now. + +The result is the pid of the child reaped, or -1 for failure +(@code{errno} says why). + +On systems that don't support waiting for a particular child, @var{pid} is +ignored. On systems like MS-DOS that don't really multitask @code{pwait} +is just a mechanism to provide a consistent interface for the caller. + +@end deftypefn + +@undocumented pfinish + + pfinish: finish generation of script + + pfinish is necessary for systems like MPW where a script is generated that + runs the requested programs. */ + +#ifdef __MSDOS__ + +/* MSDOS doesn't multitask, but for the sake of a consistent interface + the code behaves like it does. pexecute runs the program, tucks the + exit code away, and returns a "pid". pwait must be called to fetch the + exit code. */ + +#include <process.h> + +/* For communicating information from pexecute to pwait. */ +static int last_pid = 0; +static int last_status = 0; +static int last_reaped = 0; + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int rc; + + last_pid++; + if (last_pid < 0) + last_pid = 1; + + if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE) + abort (); + +#ifdef __DJGPP__ + /* ??? What are the possible return values from spawnv? */ + rc = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (P_WAIT, program, argv); +#else + char *scmd, *rf; + FILE *argfile; + int i, el = flags & PEXECUTE_SEARCH ? 4 : 0; + + if (temp_base == 0) + temp_base = choose_temp_base (); + scmd = (char *) xmalloc (strlen (program) + strlen (temp_base) + 6 + el); + rf = scmd + strlen(program) + 2 + el; + sprintf (scmd, "%s%s @%s.gp", program, + (flags & PEXECUTE_SEARCH ? ".exe" : ""), temp_base); + argfile = fopen (rf, "w"); + if (argfile == 0) + { + int errno_save = errno; + free (scmd); + errno = errno_save; + *errmsg_fmt = "cannot open `%s.gp'"; + *errmsg_arg = temp_base; + return -1; + } + + 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); + + rc = system (scmd); + + { + int errno_save = errno; + remove (rf); + free (scmd); + errno = errno_save; + } +#endif + + if (rc == -1) + { + *errmsg_fmt = install_error_msg; + *errmsg_arg = (char *)program; + return -1; + } + + /* Tuck the status away for pwait, and return a "pid". */ + last_status = rc << 8; + return last_pid; +} + +/* Use ECHILD if available, otherwise use EINVAL. */ +#ifdef ECHILD +#define PWAIT_ERROR ECHILD +#else +#define PWAIT_ERROR EINVAL +#endif + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + /* On MSDOS each pexecute must be followed by it's associated pwait. */ + if (pid != last_pid + /* Called twice for the same child? */ + || pid == last_reaped) + { + errno = PWAIT_ERROR; + return -1; + } + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ +#ifdef __DJGPP__ + *status = (last_status >> 8); +#else + *status = last_status; +#endif + last_reaped = last_pid; + return last_pid; +} + +#endif /* MSDOS */ + +#if defined (_WIN32) && ! defined (_UWIN) + +#include <process.h> + +#ifdef __CYGWIN__ + +#define fix_argv(argvec) (argvec) + +extern int _spawnv (); +extern int _spawnvp (); + +#else /* ! __CYGWIN__ */ + +/* This is a kludge to get around the Microsoft C spawn functions' propensity + to remove the outermost set of double quotes from all arguments. */ + +static const char * const * +fix_argv (argvec) + char **argvec; +{ + int i; + + for (i = 1; argvec[i] != 0; i++) + { + int len, j; + char *temp, *newtemp; + + temp = argvec[i]; + len = strlen (temp); + for (j = 0; j < len; j++) + { + if (temp[j] == '"') + { + newtemp = xmalloc (len + 2); + strncpy (newtemp, temp, j); + newtemp [j] = '\\'; + strncpy (&newtemp [j+1], &temp [j], len-j); + newtemp [len+1] = 0; + temp = newtemp; + len++; + j++; + } + } + + argvec[i] = temp; + } + + for (i = 0; argvec[i] != 0; i++) + { + if (strpbrk (argvec[i], " \t")) + { + int len, trailing_backslash; + char *temp; + + len = strlen (argvec[i]); + trailing_backslash = 0; + + /* There is an added complication when an arg with embedded white + space ends in a backslash (such as in the case of -iprefix arg + passed to cpp). The resulting quoted strings gets misinterpreted + by the command interpreter -- it thinks that the ending quote + is escaped by the trailing backslash and things get confused. + We handle this case by escaping the trailing backslash, provided + it was not escaped in the first place. */ + if (len > 1 + && argvec[i][len-1] == '\\' + && argvec[i][len-2] != '\\') + { + trailing_backslash = 1; + ++len; /* to escape the final backslash. */ + } + + len += 2; /* and for the enclosing quotes. */ + + temp = xmalloc (len + 1); + temp[0] = '"'; + strcpy (temp + 1, argvec[i]); + if (trailing_backslash) + temp[len-2] = '\\'; + temp[len-1] = '"'; + temp[len] = '\0'; + + argvec[i] = temp; + } + } + + return (const char * const *) argvec; +} +#endif /* __CYGWIN__ */ + +#include <io.h> +#include <fcntl.h> +#include <signal.h> + +/* mingw32 headers may not define the following. */ + +#ifndef _P_WAIT +# define _P_WAIT 0 +# define _P_NOWAIT 1 +# define _P_OVERLAY 2 +# define _P_NOWAITO 3 +# define _P_DETACH 4 + +# define WAIT_CHILD 0 +# define WAIT_GRANDCHILD 1 +#endif + +/* Win32 supports pipes */ +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int pid; + int pdes[2], org_stdin, org_stdout; + int input_desc, output_desc; + int retries, sleep_interval; + + /* Pipe waiting from last process, to be used as input for the next one. + Value is STDIN_FILE_NO if no pipe is waiting + (i.e. the next command is the first of a group). */ + static int last_pipe_input; + + /* If this is the first process, initialize. */ + if (flags & PEXECUTE_FIRST) + last_pipe_input = STDIN_FILE_NO; + + input_desc = last_pipe_input; + + /* If this isn't the last process, make a pipe for its output, + and record it as waiting to be the input to the next process. */ + if (! (flags & PEXECUTE_LAST)) + { + if (_pipe (pdes, 256, O_BINARY) < 0) + { + *errmsg_fmt = "pipe"; + *errmsg_arg = NULL; + return -1; + } + output_desc = pdes[WRITE_PORT]; + last_pipe_input = pdes[READ_PORT]; + } + else + { + /* Last process. */ + output_desc = STDOUT_FILE_NO; + last_pipe_input = STDIN_FILE_NO; + } + + if (input_desc != STDIN_FILE_NO) + { + org_stdin = dup (STDIN_FILE_NO); + dup2 (input_desc, STDIN_FILE_NO); + close (input_desc); + } + + if (output_desc != STDOUT_FILE_NO) + { + org_stdout = dup (STDOUT_FILE_NO); + dup2 (output_desc, STDOUT_FILE_NO); + close (output_desc); + } + + pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv) + (_P_NOWAIT, program, fix_argv(argv)); + + if (input_desc != STDIN_FILE_NO) + { + dup2 (org_stdin, STDIN_FILE_NO); + close (org_stdin); + } + + if (output_desc != STDOUT_FILE_NO) + { + dup2 (org_stdout, STDOUT_FILE_NO); + close (org_stdout); + } + + if (pid == -1) + { + *errmsg_fmt = install_error_msg; + *errmsg_arg = program; + return -1; + } + + return pid; +} + +/* MS CRTDLL doesn't return enough information in status to decide if the + child exited due to a signal or not, rather it simply returns an + integer with the exit code of the child; eg., if the child exited with + an abort() call and didn't have a handler for SIGABRT, it simply returns + with status = 3. We fix the status code to conform to the usual WIF* + macros. Note that WIFSIGNALED will never be true under CRTDLL. */ + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ +#ifdef __CYGWIN__ + return wait (status); +#else + int termstat; + + pid = _cwait (&termstat, pid, WAIT_CHILD); + + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + + /* cwait returns the child process exit code in termstat. + A value of 3 indicates that the child caught a signal, but not + which one. Since only SIGABRT, SIGFPE and SIGINT do anything, we + report SIGABRT. */ + if (termstat == 3) + *status = SIGABRT; + else + *status = (((termstat) & 0xff) << 8); + + return pid; +#endif /* __CYGWIN__ */ +} + +#endif /* _WIN32 && ! _UWIN */ + +#ifdef OS2 + +/* ??? Does OS2 have process.h? */ +extern int spawnv (); +extern int spawnvp (); + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int pid; + + if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE) + abort (); + /* ??? Presumably 1 == _P_NOWAIT. */ + pid = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv); + if (pid == -1) + { + *errmsg_fmt = install_error_msg; + *errmsg_arg = program; + return -1; + } + return pid; +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + int pid = wait (status); + return pid; +} + +#endif /* OS2 */ + +#ifdef MPW + +/* MPW pexecute doesn't actually run anything; instead, it writes out + script commands that, when run, will do the actual executing. + + For example, in GCC's case, GCC will write out several script commands: + + cpp ... + cc1 ... + as ... + ld ... + + and then exit. None of the above programs will have run yet. The task + that called GCC will then execute the script and cause cpp,etc. to run. + The caller must invoke pfinish before calling exit. This adds + the finishing touches to the generated script. */ + +static int first_time = 1; + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + char tmpprogram[255]; + char *cp, *tmpname; + int i; + + mpwify_filename (program, tmpprogram); + if (first_time) + { + printf ("Set Failed 0\n"); + first_time = 0; + } + + fputs ("If {Failed} == 0\n", stdout); + /* If being verbose, output a copy of the command. It should be + accurate enough and escaped enough to be "clickable". */ + if (flags & PEXECUTE_VERBOSE) + { + fputs ("\tEcho ", stdout); + fputc ('\'', stdout); + fputs (tmpprogram, stdout); + fputc ('\'', stdout); + fputc (' ', stdout); + for (i=1; argv[i]; i++) + { + fputc ('\'', stdout); + /* See if we have an argument that needs fixing. */ + if (strchr(argv[i], '/')) + { + tmpname = (char *) xmalloc (256); + mpwify_filename (argv[i], tmpname); + argv[i] = tmpname; + } + for (cp = argv[i]; *cp; cp++) + { + /* Write an Option-d escape char in front of special chars. */ + if (strchr("'+", *cp)) + fputc ('\266', stdout); + fputc (*cp, stdout); + } + fputc ('\'', stdout); + fputc (' ', stdout); + } + fputs ("\n", stdout); + } + fputs ("\t", stdout); + fputs (tmpprogram, stdout); + fputc (' ', stdout); + + for (i=1; argv[i]; i++) + { + /* See if we have an argument that needs fixing. */ + if (strchr(argv[i], '/')) + { + tmpname = (char *) xmalloc (256); + mpwify_filename (argv[i], tmpname); + argv[i] = tmpname; + } + if (strchr (argv[i], ' ')) + fputc ('\'', stdout); + for (cp = argv[i]; *cp; cp++) + { + /* Write an Option-d escape char in front of special chars. */ + if (strchr("'+", *cp)) + fputc ('\266', stdout); + fputc (*cp, stdout); + } + if (strchr (argv[i], ' ')) + fputc ('\'', stdout); + fputc (' ', stdout); + } + + fputs ("\n", stdout); + + /* Output commands that arrange to clean up and exit if a failure occurs. + We have to be careful to collect the status from the program that was + run, rather than some other script command. Also, we don't exit + immediately, since necessary cleanups are at the end of the script. */ + fputs ("\tSet TmpStatus {Status}\n", stdout); + fputs ("\tIf {TmpStatus} != 0\n", stdout); + fputs ("\t\tSet Failed {TmpStatus}\n", stdout); + fputs ("\tEnd\n", stdout); + fputs ("End\n", stdout); + + /* We're just composing a script, can't fail here. */ + return 0; +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + *status = 0; + return 0; +} + +/* Write out commands that will exit with the correct error code + if something in the script failed. */ + +void +pfinish () +{ + printf ("\tExit \"{Failed}\"\n"); +} + +#endif /* MPW */ + +/* include for Unix-like environments but not for Dos-like environments */ +#if ! defined (__MSDOS__) && ! defined (OS2) && ! defined (MPW) \ + && ! (defined (_WIN32) && ! defined (_UWIN)) + +extern int execv (); +extern int execvp (); + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base ATTRIBUTE_UNUSED; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int (*func)() = (flags & PEXECUTE_SEARCH ? execvp : execv); + int pid; + int pdes[2]; + int input_desc, output_desc; + int retries, sleep_interval; + /* Pipe waiting from last process, to be used as input for the next one. + Value is STDIN_FILE_NO if no pipe is waiting + (i.e. the next command is the first of a group). */ + static int last_pipe_input; + + /* If this is the first process, initialize. */ + if (flags & PEXECUTE_FIRST) + last_pipe_input = STDIN_FILE_NO; + + input_desc = last_pipe_input; + + /* If this isn't the last process, make a pipe for its output, + and record it as waiting to be the input to the next process. */ + if (! (flags & PEXECUTE_LAST)) + { + if (pipe (pdes) < 0) + { + *errmsg_fmt = "pipe"; + *errmsg_arg = NULL; + return -1; + } + output_desc = pdes[WRITE_PORT]; + last_pipe_input = pdes[READ_PORT]; + } + else + { + /* Last process. */ + output_desc = STDOUT_FILE_NO; + last_pipe_input = STDIN_FILE_NO; + } + + /* Fork a subprocess; wait and retry if it fails. */ + sleep_interval = 1; + pid = -1; + for (retries = 0; retries < 4; retries++) + { + pid = fork (); + if (pid >= 0) + break; + sleep (sleep_interval); + sleep_interval *= 2; + } + + switch (pid) + { + case -1: + *errmsg_fmt = "fork"; + *errmsg_arg = NULL; + return -1; + + case 0: /* child */ + /* Move the input and output pipes into place, if necessary. */ + if (input_desc != STDIN_FILE_NO) + { + close (STDIN_FILE_NO); + dup (input_desc); + close (input_desc); + } + if (output_desc != STDOUT_FILE_NO) + { + close (STDOUT_FILE_NO); + dup (output_desc); + close (output_desc); + } + + /* Close the parent's descs that aren't wanted here. */ + if (last_pipe_input != STDIN_FILE_NO) + close (last_pipe_input); + + /* Exec the program. */ + (*func) (program, argv); + + fprintf (stderr, "%s: ", this_pname); + fprintf (stderr, install_error_msg, program); + fprintf (stderr, ": %s\n", xstrerror (errno)); + _exit (-1); + /* NOTREACHED */ + return 0; + + default: + /* In the parent, after forking. + Close the descriptors that we made for this child. */ + if (input_desc != STDIN_FILE_NO) + close (input_desc); + if (output_desc != STDOUT_FILE_NO) + close (output_desc); + + /* Return child's process number. */ + return pid; + } +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags ATTRIBUTE_UNUSED; +{ + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ +#ifdef VMS + pid = waitpid (-1, status, 0); +#else + pid = wait (status); +#endif + return pid; +} + +#endif /* ! __MSDOS__ && ! OS2 && ! MPW && ! (_WIN32 && ! _UWIN) */ diff --git a/contrib/gcc/print-tree.c b/contrib/gcc/print-tree.c index 57b07ac..2965d6e 100644 --- a/contrib/gcc/print-tree.c +++ b/contrib/gcc/print-tree.c @@ -1,6 +1,6 @@ /* Prints out tree in human readable form - GCC Copyright (C) 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #include "config.h" @@ -28,7 +28,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "real.h" #include "ggc.h" #include "langhooks.h" -#include "tree-iterator.h" /* Define the hash table of nodes already seen. Such nodes are not repeated; brief cross-references are used. */ @@ -50,29 +49,19 @@ static struct bucket **table; void debug_tree (tree node) { - table = XCNEWVEC (struct bucket *, HASH_SIZE); + table = xcalloc (HASH_SIZE, sizeof (struct bucket *)); print_node (stderr, "", node, 0); free (table); table = 0; putc ('\n', stderr); } -/* Print PREFIX and ADDR to FILE. */ -void -dump_addr (FILE *file, const char *prefix, void *addr) -{ - if (flag_dump_noaddr || flag_dump_unnumbered) - fprintf (file, "%s#", prefix); - else - fprintf (file, "%s%p", prefix, addr); -} - /* Print a node in brief fashion, with just the code, address and name. */ void print_node_brief (FILE *file, const char *prefix, tree node, int indent) { - enum tree_code_class class; + char class; if (node == 0) return; @@ -83,21 +72,15 @@ print_node_brief (FILE *file, const char *prefix, tree node, int indent) name if any. */ if (indent > 0) fprintf (file, " "); - fprintf (file, "%s <%s", prefix, tree_code_name[(int) TREE_CODE (node)]); - dump_addr (file, " ", node); + fprintf (file, "%s <%s " HOST_PTR_PRINTF, + prefix, tree_code_name[(int) TREE_CODE (node)], (char *) node); - if (class == tcc_declaration) + if (class == 'd') { if (DECL_NAME (node)) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node))); - else if (TREE_CODE (node) == LABEL_DECL - && LABEL_DECL_UID (node) != -1) - fprintf (file, " L." HOST_WIDE_INT_PRINT_DEC, LABEL_DECL_UID (node)); - else - fprintf (file, " %c.%u", TREE_CODE (node) == CONST_DECL ? 'C' : 'D', - DECL_UID (node)); } - else if (class == tcc_type) + else if (class == 't') { if (TYPE_NAME (node)) { @@ -138,7 +121,7 @@ print_node_brief (FILE *file, const char *prefix, tree node, int indent) d = TREE_REAL_CST (node); if (REAL_VALUE_ISINF (d)) - fprintf (file, REAL_VALUE_NEGATIVE (d) ? " -Inf" : " Inf"); + fprintf (file, " Inf"); else if (REAL_VALUE_ISNAN (d)) fprintf (file, " Nan"); else @@ -173,17 +156,15 @@ print_node (FILE *file, const char *prefix, tree node, int indent) int hash; struct bucket *b; enum machine_mode mode; - enum tree_code_class class; + char class; int len; + int first_rtl; int i; - expanded_location xloc; - enum tree_code code; if (node == 0) return; - - code = TREE_CODE (node); - class = TREE_CODE_CLASS (code); + + 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 @@ -195,7 +176,7 @@ print_node (FILE *file, const char *prefix, tree node, int indent) return; } - if (indent > 8 && (class == tcc_type || class == tcc_declaration)) + if (indent > 8 && (class == 't' || class == 'd')) { print_node_brief (file, prefix, node, indent); return; @@ -219,7 +200,7 @@ print_node (FILE *file, const char *prefix, tree node, int indent) } /* Add this node to the table. */ - b = XNEW (struct bucket); + b = xmalloc (sizeof (struct bucket)); b->node = node; b->next = table[hash]; table[hash] = b; @@ -228,22 +209,16 @@ print_node (FILE *file, const char *prefix, tree node, int indent) 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)]); - dump_addr (file, " ", node); + fprintf (file, "%s <%s " HOST_PTR_PRINTF, + prefix, tree_code_name[(int) TREE_CODE (node)], (void *) node); /* Print the name, if any. */ - if (class == tcc_declaration) + if (class == 'd') { if (DECL_NAME (node)) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node))); - else if (TREE_CODE (node) == LABEL_DECL - && LABEL_DECL_UID (node) != -1) - fprintf (file, " L." HOST_WIDE_INT_PRINT_DEC, LABEL_DECL_UID (node)); - else - fprintf (file, " %c.%u", TREE_CODE (node) == CONST_DECL ? 'C' : 'D', - DECL_UID (node)); } - else if (class == tcc_type) + else if (class == 't') { if (TYPE_NAME (node)) { @@ -270,22 +245,18 @@ print_node (FILE *file, const char *prefix, tree node, int indent) indent_to (file, indent + 3); } - if (!TYPE_P (node) && TREE_SIDE_EFFECTS (node)) + if (TREE_SIDE_EFFECTS (node)) fputs (" side-effects", file); - - if (TYPE_P (node) ? TYPE_READONLY (node) : TREE_READONLY (node)) + if (TREE_READONLY (node)) fputs (" readonly", file); - if (!TYPE_P (node) && TREE_CONSTANT (node)) + if (TREE_CONSTANT (node)) fputs (" constant", file); - else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node)) - fputs (" sizes-gimplified", file); - - if (TREE_INVARIANT (node)) - fputs (" invariant", 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)) @@ -302,8 +273,6 @@ print_node (FILE *file, const char *prefix, tree node, int indent) fputs (" static", file); if (TREE_DEPRECATED (node)) fputs (" deprecated", file); - if (TREE_VISITED (node)) - fputs (" visited", file); if (TREE_LANG_FLAG_0 (node)) fputs (" tree_0", file); if (TREE_LANG_FLAG_1 (node)) @@ -323,32 +292,27 @@ print_node (FILE *file, const char *prefix, tree node, int indent) switch (TREE_CODE_CLASS (TREE_CODE (node))) { - case tcc_declaration: - if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) - { - if (DECL_UNSIGNED (node)) - fputs (" unsigned", file); - if (DECL_IGNORED_P (node)) - fputs (" ignored", file); - if (DECL_ABSTRACT (node)) - fputs (" abstract", file); - if (DECL_EXTERNAL (node)) - fputs (" external", file); - if (DECL_NONLOCAL (node)) - fputs (" nonlocal", file); - } - if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) - { - if (DECL_WEAK (node)) - fputs (" weak", file); - if (DECL_IN_SYSTEM_HEADER (node)) - fputs (" in_system_header", file); - } - if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL) - && TREE_CODE (node) != LABEL_DECL + case 'd': + mode = DECL_MODE (node); + + if (DECL_IGNORED_P (node)) + fputs (" ignored", file); + if (DECL_ABSTRACT (node)) + fputs (" abstract", file); + if (DECL_IN_SYSTEM_HEADER (node)) + fputs (" in_system_header", file); + if (DECL_COMMON (node)) + fputs (" common", file); + if (DECL_EXTERNAL (node)) + fputs (" external", file); + if (DECL_WEAK (node)) + fputs (" weak", file); + if (DECL_REGISTER (node) && TREE_CODE (node) != FIELD_DECL && TREE_CODE (node) != FUNCTION_DECL - && DECL_REGISTER (node)) + && TREE_CODE (node) != LABEL_DECL) fputs (" regdecl", file); + if (DECL_NONLOCAL (node)) + fputs (" nonlocal", file); if (TREE_CODE (node) == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node)) fputs (" suppress-debug", file); @@ -367,132 +331,94 @@ print_node (FILE *file, const char *prefix, tree node, int indent) if (TREE_CODE (node) == FIELD_DECL && DECL_NONADDRESSABLE_P (node)) fputs (" nonaddressable", file); + if (TREE_CODE (node) == LABEL_DECL && DECL_TOO_LATE (node)) + fputs (" too-late", file); if (TREE_CODE (node) == LABEL_DECL && DECL_ERROR_ISSUED (node)) fputs (" error-issued", file); if (TREE_CODE (node) == VAR_DECL && DECL_IN_TEXT_SECTION (node)) fputs (" in-text-section", file); - if (TREE_CODE (node) == VAR_DECL && DECL_COMMON (node)) - fputs (" common", file); - if (TREE_CODE (node) == VAR_DECL && DECL_THREAD_LOCAL_P (node)) - { - enum tls_model kind = DECL_TLS_MODEL (node); - switch (kind) - { - case TLS_MODEL_GLOBAL_DYNAMIC: - fputs (" tls-global-dynamic", file); - break; - case TLS_MODEL_LOCAL_DYNAMIC: - fputs (" tls-local-dynamic", file); - break; - case TLS_MODEL_INITIAL_EXEC: - fputs (" tls-initial-exec", file); - break; - case TLS_MODEL_LOCAL_EXEC: - fputs (" tls-local-exec", file); - break; - default: - gcc_unreachable (); - } - } + if (TREE_CODE (node) == VAR_DECL && DECL_THREAD_LOCAL (node)) + fputs (" thread-local", file); - if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) - { - if (DECL_VIRTUAL_P (node)) - fputs (" virtual", file); - if (DECL_PRESERVE_P (node)) - fputs (" preserve", 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); - - mode = DECL_MODE (node); - fprintf (file, " %s", GET_MODE_NAME (mode)); - } + if (TREE_CODE (node) == PARM_DECL && DECL_TRANSPARENT_UNION (node)) + fputs (" transparent-union", file); - if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS) && DECL_DEFER_OUTPUT (node)) + if (DECL_VIRTUAL_P (node)) + fputs (" virtual", file); + if (DECL_DEFER_OUTPUT (node)) fputs (" defer-output", 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); - xloc = expand_location (DECL_SOURCE_LOCATION (node)); - fprintf (file, " file %s line %d", xloc.file, xloc.line); + fprintf (file, " %s", GET_MODE_NAME (mode)); + fprintf (file, " file %s line %d", + DECL_SOURCE_FILE (node), DECL_SOURCE_LINE (node)); - if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) - { - print_node (file, "size", DECL_SIZE (node), indent + 4); - print_node (file, "unit size", DECL_SIZE_UNIT (node), indent + 4); - - if (TREE_CODE (node) != FUNCTION_DECL - || DECL_INLINE (node) || DECL_BUILT_IN (node)) - indent_to (file, indent + 3); - - if (TREE_CODE (node) != FUNCTION_DECL) - { - if (DECL_USER_ALIGN (node)) - fprintf (file, " user"); - - fprintf (file, " align %d", DECL_ALIGN (node)); - if (TREE_CODE (node) == FIELD_DECL) - fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED, - DECL_OFFSET_ALIGN (node)); - } - else if (DECL_BUILT_IN (node)) - { - if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD) - fprintf (file, " built-in BUILT_IN_MD %d", DECL_FUNCTION_CODE (node)); - else - fprintf (file, " built-in %s:%s", - built_in_class_names[(int) DECL_BUILT_IN_CLASS (node)], - built_in_names[(int) DECL_FUNCTION_CODE (node)]); - } - - if (DECL_POINTER_ALIAS_SET_KNOWN_P (node)) - fprintf (file, " alias set " HOST_WIDE_INT_PRINT_DEC, - DECL_POINTER_ALIAS_SET (node)); + print_node (file, "size", DECL_SIZE (node), indent + 4); + print_node (file, "unit size", DECL_SIZE_UNIT (node), indent + 4); + + if (TREE_CODE (node) != FUNCTION_DECL + || DECL_INLINE (node) || DECL_BUILT_IN (node)) + indent_to (file, indent + 3); + + if (TREE_CODE (node) != FUNCTION_DECL) + { + if (DECL_USER_ALIGN (node)) + fprintf (file, " user"); + + fprintf (file, " align %d", DECL_ALIGN (node)); + if (TREE_CODE (node) == FIELD_DECL) + fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED, + DECL_OFFSET_ALIGN (node)); + } + else if (DECL_BUILT_IN (node)) + { + if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD) + fprintf (file, " built-in BUILT_IN_MD %d", DECL_FUNCTION_CODE (node)); + else + fprintf (file, " built-in %s:%s", + built_in_class_names[(int) DECL_BUILT_IN_CLASS (node)], + built_in_names[(int) DECL_FUNCTION_CODE (node)]); } + + if (DECL_POINTER_ALIAS_SET_KNOWN_P (node)) + fprintf (file, " alias set " HOST_WIDE_INT_PRINT_DEC, + DECL_POINTER_ALIAS_SET (node)); + if (TREE_CODE (node) == FIELD_DECL) { print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4); print_node (file, "bit offset", DECL_FIELD_BIT_OFFSET (node), indent + 4); - if (DECL_BIT_FIELD_TYPE (node)) - print_node (file, "bit_field_type", DECL_BIT_FIELD_TYPE (node), - indent + 4); } print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4); + print_node_brief (file, "attributes", + DECL_ATTRIBUTES (node), indent + 4); + print_node_brief (file, "abstract_origin", + DECL_ABSTRACT_ORIGIN (node), indent + 4); - if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) - { - print_node_brief (file, "attributes", - DECL_ATTRIBUTES (node), indent + 4); - print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4); - } - if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)) - { - print_node_brief (file, "abstract_origin", - DECL_ABSTRACT_ORIGIN (node), indent + 4); - } - if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON)) - { - print_node (file, "arguments", DECL_ARGUMENT_FLD (node), indent + 4); - print_node (file, "result", DECL_RESULT_FLD (node), indent + 4); - } + print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4); + print_node (file, "result", DECL_RESULT_FLD (node), indent + 4); + print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4); - lang_hooks.print_decl (file, node, indent); + (*lang_hooks.print_decl) (file, node, indent); if (DECL_RTL_SET_P (node)) { @@ -503,6 +429,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent) if (TREE_CODE (node) == PARM_DECL) { print_node (file, "arg-type", DECL_ARG_TYPE (node), indent + 4); + print_node (file, "arg-type-as-written", + DECL_ARG_TYPE_AS_WRITTEN (node), indent + 4); if (DECL_INCOMING_RTL (node) != 0) { @@ -512,25 +440,13 @@ print_node (FILE *file, const char *prefix, tree node, int indent) } } else if (TREE_CODE (node) == FUNCTION_DECL - && DECL_STRUCT_FUNCTION (node) != 0) + && DECL_SAVED_INSNS (node) != 0) { indent_to (file, indent + 4); - dump_addr (file, "saved-insns ", DECL_STRUCT_FUNCTION (node)); + fprintf (file, "saved-insns " HOST_PTR_PRINTF, + (void *) DECL_SAVED_INSNS (node)); } - if ((TREE_CODE (node) == VAR_DECL || TREE_CODE (node) == PARM_DECL) - && DECL_HAS_VALUE_EXPR_P (node)) - print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4); - - if (TREE_CODE (node) == STRUCT_FIELD_TAG) - { - fprintf (file, " sft size " HOST_WIDE_INT_PRINT_DEC, - SFT_SIZE (node)); - fprintf (file, " sft offset " HOST_WIDE_INT_PRINT_DEC, - SFT_OFFSET (node)); - print_node_brief (file, "parent var", SFT_PARENT_VAR (node), - indent + 4); - } /* Print the decl chain only if decl is at second level. */ if (indent == 4) print_node (file, "chain", TREE_CHAIN (node), indent + 4); @@ -538,10 +454,7 @@ print_node (FILE *file, const char *prefix, tree node, int indent) print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; - case tcc_type: - if (TYPE_UNSIGNED (node)) - fputs (" unsigned", file); - + case 't': /* The no-force-blk flag is used for different things in different types. */ if ((TREE_CODE (node) == RECORD_TYPE @@ -615,10 +528,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent) if (TREE_CODE (node) == ENUMERAL_TYPE) print_node (file, "values", TYPE_VALUES (node), indent + 4); - else if (TREE_CODE (node) == ARRAY_TYPE) + else 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) == VECTOR_TYPE) - fprintf (file, " nunits %d", (int) TYPE_VECTOR_SUBPARTS (node)); else if (TREE_CODE (node) == RECORD_TYPE || TREE_CODE (node) == UNION_TYPE || TREE_CODE (node) == QUAL_UNION_TYPE) @@ -638,7 +549,7 @@ print_node (FILE *file, const char *prefix, tree node, int indent) if (TYPE_CONTEXT (node)) print_node_brief (file, "context", TYPE_CONTEXT (node), indent + 4); - lang_hooks.print_type (file, node, indent); + (*lang_hooks.print_type) (file, node, indent); if (TYPE_POINTER_TO (node) || TREE_CHAIN (node)) indent_to (file, indent + 3); @@ -650,14 +561,21 @@ print_node (FILE *file, const char *prefix, tree node, int indent) print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; - case tcc_expression: - case tcc_comparison: - case tcc_unary: - case tcc_binary: - case tcc_reference: - case tcc_statement: - if (TREE_CODE (node) == BIT_FIELD_REF && BIT_FIELD_REF_UNSIGNED (node)) - fputs (" unsigned", file); + case 'b': + print_node (file, "vars", BLOCK_VARS (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); + break; + + case 'e': + case '<': + case '1': + case '2': + case 'r': + case 's': if (TREE_CODE (node) == BIND_EXPR) { print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4); @@ -668,19 +586,44 @@ print_node (FILE *file, const char *prefix, tree node, int indent) len = TREE_CODE_LENGTH (TREE_CODE (node)); + /* Some nodes contain rtx's, not trees, + after a certain point. Print the rtx's as rtx's. */ + first_rtl = first_rtl_op (TREE_CODE (node)); + for (i = 0; i < len; i++) { - char temp[10]; + if (i >= first_rtl) + { + indent_to (file, indent + 4); + fprintf (file, "rtl %d ", i); + if (TREE_OPERAND (node, i)) + print_rtl (file, (rtx) 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); + sprintf (temp, "arg %d", i); + print_node (file, temp, TREE_OPERAND (node, i), indent + 4); + } } + if (TREE_CODE (node) == EXPR_WITH_FILE_LOCATION) + { + indent_to (file, indent+4); + fprintf (file, "%s:%d:%d", + (EXPR_WFL_FILENAME_NODE (node ) ? + EXPR_WFL_FILENAME (node) : "(no file info)"), + EXPR_WFL_LINENO (node), EXPR_WFL_COLNO (node)); + } print_node (file, "chain", TREE_CHAIN (node), indent + 4); break; - case tcc_constant: - case tcc_exceptional: + case 'c': + case 'x': switch (TREE_CODE (node)) { case INTEGER_CST: @@ -709,7 +652,7 @@ print_node (FILE *file, const char *prefix, tree node, int indent) d = TREE_REAL_CST (node); if (REAL_VALUE_ISINF (d)) - fprintf (file, REAL_VALUE_NEGATIVE (d) ? " -Inf" : " Inf"); + fprintf (file, " Inf"); else if (REAL_VALUE_ISNAN (d)) fprintf (file, " Nan"); else @@ -765,7 +708,7 @@ print_node (FILE *file, const char *prefix, tree node, int indent) break; case IDENTIFIER_NODE: - lang_hooks.print_identifier (file, node, indent); + (*lang_hooks.print_identifier) (file, node, indent); break; case TREE_LIST: @@ -786,91 +729,14 @@ print_node (FILE *file, const char *prefix, tree node, int indent) } break; - case STATEMENT_LIST: - dump_addr (file, " head ", node->stmt_list.head); - dump_addr (file, " tail ", node->stmt_list.tail); - fprintf (file, " stmts"); - { - tree_stmt_iterator i; - for (i = tsi_start (node); !tsi_end_p (i); tsi_next (&i)) - { - /* Not printing the addresses of the (not-a-tree) - 'struct tree_stmt_list_node's. */ - dump_addr (file, " ", tsi_stmt (i)); - } - fprintf (file, "\n"); - for (i = tsi_start (node); !tsi_end_p (i); tsi_next (&i)) - { - /* Not printing the addresses of the (not-a-tree) - 'struct tree_stmt_list_node's. */ - print_node (file, "stmt", tsi_stmt (i), indent + 4); - } - } - print_node (file, "chain", TREE_CHAIN (node), indent + 4); - break; - - case BLOCK: - print_node (file, "vars", BLOCK_VARS (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); - break; - - case SSA_NAME: - print_node_brief (file, "var", SSA_NAME_VAR (node), indent + 4); - print_node_brief (file, "def_stmt", - SSA_NAME_DEF_STMT (node), indent + 4); - - indent_to (file, indent + 4); - fprintf (file, "version %u", SSA_NAME_VERSION (node)); - if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (node)) - fprintf (file, " in-abnormal-phi"); - if (SSA_NAME_IN_FREE_LIST (node)) - fprintf (file, " in-free-list"); - - if (SSA_NAME_PTR_INFO (node) - || SSA_NAME_VALUE (node)) - { - indent_to (file, indent + 3); - if (SSA_NAME_PTR_INFO (node)) - dump_addr (file, " ptr-info ", SSA_NAME_PTR_INFO (node)); - if (SSA_NAME_VALUE (node)) - dump_addr (file, " value ", SSA_NAME_VALUE (node)); - } - break; - - case OMP_CLAUSE: - { - int i; - fprintf (file, " %s", - omp_clause_code_name[OMP_CLAUSE_CODE (node)]); - for (i = 0; i < omp_clause_num_ops[OMP_CLAUSE_CODE (node)]; i++) - { - indent_to (file, indent + 4); - fprintf (file, "op %d:", i); - print_node_brief (file, "", OMP_CLAUSE_OPERAND (node, i), 0); - } - } - break; - default: - if (EXCEPTIONAL_CLASS_P (node)) - lang_hooks.print_xnode (file, node, indent); + if (TREE_CODE_CLASS (TREE_CODE (node)) == 'x') + (*lang_hooks.print_xnode) (file, node, indent); break; } break; } - if (EXPR_HAS_LOCATION (node)) - { - expanded_location xloc = expand_location (EXPR_LOCATION (node)); - indent_to (file, indent+4); - fprintf (file, "%s:%d", xloc.file, xloc.line); - } - fprintf (file, ">"); } diff --git a/contrib/gcc/recog.c b/contrib/gcc/recog.c index cd1cb7d..2224c5a 100644 --- a/contrib/gcc/recog.c +++ b/contrib/gcc/recog.c @@ -1,6 +1,6 @@ /* Subroutines used by or related to instruction recognition. Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 - 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #include "config.h" @@ -31,7 +31,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "hard-reg-set.h" #include "recog.h" #include "regs.h" -#include "addresses.h" #include "expr.h" #include "function.h" #include "flags.h" @@ -40,8 +39,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "basic-block.h" #include "output.h" #include "reload.h" -#include "timevar.h" -#include "tree-pass.h" #ifndef STACK_PUSH_CODE #ifdef STACK_GROWS_DOWNWARD @@ -110,6 +107,22 @@ init_recog (void) volatile_ok = 1; } +/* Try recognizing the instruction INSN, + and return the code number that results. + Remember the code so that repeated calls do not + need to spend the time for actual rerecognition. + + This function is the normal interface to instruction recognition. + The automatically-generated function `recog' is normally called + through this one. (The only exception is in combine.c.) */ + +int +recog_memoized_1 (rtx insn) +{ + if (INSN_CODE (insn) < 0) + INSN_CODE (insn) = recog (PATTERN (insn), insn, 0); + return INSN_CODE (insn); +} /* Check that X is an insn-body for an `asm' with operands and that the operands mentioned in it are legitimate. */ @@ -198,7 +211,8 @@ validate_change (rtx object, rtx *loc, rtx new, int in_group) if (old == new || rtx_equal_p (old, new)) return 1; - gcc_assert (in_group != 0 || num_changes == 0); + if (in_group == 0 && num_changes != 0) + abort (); *loc = new; @@ -219,7 +233,7 @@ validate_change (rtx object, rtx *loc, rtx new, int in_group) changes[num_changes].loc = loc; changes[num_changes].old = old; - if (object && !MEM_P (object)) + if (object && GET_CODE (object) != MEM) { /* Set INSN_CODE to force rerecognition of insn. Save old code in case invalid. */ @@ -238,7 +252,6 @@ validate_change (rtx object, rtx *loc, rtx new, int in_group) return apply_change_group (); } - /* This subroutine of apply_change_group verifies whether the changes to INSN were valid; i.e. whether INSN can still be recognized. */ @@ -298,11 +311,11 @@ num_changes_pending (void) return num_changes; } -/* Tentatively apply the changes numbered NUM and up. +/* Apply a group of changes previously issued with `validate_change'. Return 1 if all changes are valid, zero otherwise. */ int -verify_changes (int num) +apply_change_group (void) { int i; rtx last_validated = NULL_RTX; @@ -316,7 +329,7 @@ verify_changes (int num) we also require that the operands meet the constraints for the insn. */ - for (i = num; i < num_changes; i++) + for (i = 0; i < num_changes; i++) { rtx object = changes[i].object; @@ -325,7 +338,7 @@ verify_changes (int num) if (object == 0 || object == last_validated) continue; - if (MEM_P (object)) + if (GET_CODE (object) == MEM) { if (! memory_address_p (GET_MODE (object), XEXP (object, 0))) break; @@ -380,38 +393,17 @@ verify_changes (int num) last_validated = object; } - return (i == num_changes); -} - -/* A group of changes has previously been issued with validate_change and - verified with verify_changes. Update the BB_DIRTY flags of the affected - blocks, and clear num_changes. */ - -void -confirm_change_group (void) -{ - int i; - basic_block bb; - - for (i = 0; i < num_changes; i++) - if (changes[i].object - && INSN_P (changes[i].object) - && (bb = BLOCK_FOR_INSN (changes[i].object))) - bb->flags |= BB_DIRTY; - - num_changes = 0; -} + if (i == num_changes) + { + basic_block bb; -/* Apply a group of changes previously issued with `validate_change'. - If all changes are valid, call confirm_change_group and return 1, - otherwise, call cancel_changes and return 0. */ + for (i = 0; i < num_changes; i++) + if (changes[i].object + && INSN_P (changes[i].object) + && (bb = BLOCK_FOR_INSN (changes[i].object))) + bb->flags |= BB_DIRTY; -int -apply_change_group (void) -{ - if (verify_changes (0)) - { - confirm_change_group (); + num_changes = 0; return 1; } else @@ -421,7 +413,6 @@ apply_change_group (void) } } - /* Return the number of changes so far in the current group. */ int @@ -442,7 +433,7 @@ cancel_changes (int num) for (i = num_changes - 1; i >= num; i--) { *changes[i].loc = changes[i].old; - if (changes[i].object && !MEM_P (changes[i].object)) + if (changes[i].object && GET_CODE (changes[i].object) != MEM) INSN_CODE (changes[i].object) = changes[i].old_code; } num_changes = num; @@ -475,7 +466,7 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) operands look similar. */ if (x == from - || (REG_P (x) && REG_P (from) + || (GET_CODE (x) == REG && GET_CODE (from) == REG && GET_MODE (x) == GET_MODE (from) && REGNO (x) == REGNO (from)) || (GET_CODE (x) == GET_CODE (from) && GET_MODE (x) == GET_MODE (from) @@ -498,9 +489,9 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == ASM_OPERANDS) { /* Verify that operands are really shared. */ - gcc_assert (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0))) - == ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP - (x, 0, j)))); + if (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0))) != + ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, j)))) + abort (); validate_replace_rtx_1 (&SET_DEST (XVECEXP (x, 0, j)), from, to, object); } @@ -530,11 +521,11 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) /* Do changes needed to keep rtx consistent. Don't do any other simplifications, as it is not our job. */ - if (SWAPPABLE_OPERANDS_P (x) + if ((GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c') && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1))) { validate_change (object, loc, - gen_rtx_fmt_ee (COMMUTATIVE_ARITH_P (x) ? code + gen_rtx_fmt_ee (GET_RTX_CLASS (code) == 'c' ? code : swap_condition (code), GET_MODE (x), XEXP (x, 1), XEXP (x, 0)), 1); @@ -595,7 +586,7 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) likely to be an insertion operation; if it was, nothing bad will happen, we might just fail in some cases). */ - if (MEM_P (XEXP (x, 0)) + if (GET_CODE (XEXP (x, 0)) == MEM && GET_CODE (XEXP (x, 1)) == CONST_INT && GET_CODE (XEXP (x, 2)) == CONST_INT && !mode_dependent_address_p (XEXP (XEXP (x, 0), 0)) @@ -650,6 +641,17 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) } } +/* Try replacing every occurrence of FROM in subexpression LOC of INSN + with TO. After all changes have been made, validate by seeing + if INSN is still valid. */ + +int +validate_replace_rtx_subexp (rtx from, rtx to, rtx insn, rtx *loc) +{ + validate_replace_rtx_1 (loc, from, to, insn); + return apply_change_group (); +} + /* Try replacing every occurrence of FROM in INSN with TO. After all changes have been made, validate by seeing if INSN is still valid. */ @@ -699,44 +701,13 @@ validate_replace_src_group (rtx from, rtx to, rtx insn) note_uses (&PATTERN (insn), validate_replace_src_1, &d); } -/* Try simplify INSN. - Invoke simplify_rtx () on every SET_SRC and SET_DEST inside the INSN's - pattern and return true if something was simplified. */ - -bool -validate_simplify_insn (rtx insn) +/* Same as validate_replace_src_group, but validate by seeing if + INSN is still valid. */ +int +validate_replace_src (rtx from, rtx to, rtx insn) { - int i; - rtx pat = NULL; - rtx newpat = NULL; - - pat = PATTERN (insn); - - if (GET_CODE (pat) == SET) - { - newpat = simplify_rtx (SET_SRC (pat)); - if (newpat && !rtx_equal_p (SET_SRC (pat), newpat)) - validate_change (insn, &SET_SRC (pat), newpat, 1); - newpat = simplify_rtx (SET_DEST (pat)); - if (newpat && !rtx_equal_p (SET_DEST (pat), newpat)) - validate_change (insn, &SET_DEST (pat), newpat, 1); - } - else if (GET_CODE (pat) == PARALLEL) - for (i = 0; i < XVECLEN (pat, 0); i++) - { - rtx s = XVECEXP (pat, 0, i); - - if (GET_CODE (XVECEXP (pat, 0, i)) == SET) - { - newpat = simplify_rtx (SET_SRC (s)); - if (newpat && !rtx_equal_p (SET_SRC (s), newpat)) - validate_change (insn, &SET_SRC (s), newpat, 1); - newpat = simplify_rtx (SET_DEST (s)); - if (newpat && !rtx_equal_p (SET_DEST (s), newpat)) - validate_change (insn, &SET_DEST (s), newpat, 1); - } - } - return ((num_changes_pending () > 0) && (apply_change_group () > 0)); + validate_replace_src_group (from, to, insn); + return apply_change_group (); } #ifdef HAVE_cc0 @@ -753,7 +724,9 @@ next_insn_tests_no_inequality (rtx insn) if (next == 0) return 0; - return (INSN_P (next) + return ((GET_CODE (next) == JUMP_INSN + || GET_CODE (next) == INSN + || GET_CODE (next) == CALL_INSN) && ! inequality_comparisons_p (PATTERN (next))); } #endif @@ -791,9 +764,9 @@ find_single_use_1 (rtx dest, rtx *loc) need just check the source. */ if (GET_CODE (SET_DEST (x)) != CC0 && GET_CODE (SET_DEST (x)) != PC - && !REG_P (SET_DEST (x)) + && GET_CODE (SET_DEST (x)) != REG && ! (GET_CODE (SET_DEST (x)) == SUBREG - && REG_P (SUBREG_REG (SET_DEST (x))) + && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x)))) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) == ((GET_MODE_SIZE (GET_MODE (SET_DEST (x))) @@ -819,7 +792,7 @@ find_single_use_1 (rtx dest, rtx *loc) if (fmt[i] == 'e') { if (dest == XEXP (x, i) - || (REG_P (dest) && REG_P (XEXP (x, i)) + || (GET_CODE (dest) == REG && GET_CODE (XEXP (x, i)) == REG && REGNO (dest) == REGNO (XEXP (x, i)))) this_result = loc; else @@ -838,8 +811,8 @@ find_single_use_1 (rtx dest, rtx *loc) for (j = XVECLEN (x, i) - 1; j >= 0; j--) { if (XVECEXP (x, i, j) == dest - || (REG_P (dest) - && REG_P (XVECEXP (x, i, j)) + || (GET_CODE (dest) == REG + && GET_CODE (XVECEXP (x, i, j)) == REG && REGNO (XVECEXP (x, i, j)) == REGNO (dest))) this_result = loc; else @@ -886,7 +859,7 @@ find_single_use (rtx dest, rtx insn, rtx *ploc) { next = NEXT_INSN (insn); if (next == 0 - || (!NONJUMP_INSN_P (next) && !JUMP_P (next))) + || (GET_CODE (next) != INSN && GET_CODE (next) != JUMP_INSN)) return 0; result = find_single_use_1 (dest, &PATTERN (next)); @@ -896,11 +869,11 @@ find_single_use (rtx dest, rtx insn, rtx *ploc) } #endif - if (reload_completed || reload_in_progress || !REG_P (dest)) + if (reload_completed || reload_in_progress || GET_CODE (dest) != REG) return 0; for (next = next_nonnote_insn (insn); - next != 0 && !LABEL_P (next); + next != 0 && GET_CODE (next) != CODE_LABEL; next = next_nonnote_insn (next)) if (INSN_P (next) && dead_or_set_p (next, dest)) { @@ -960,7 +933,9 @@ general_operand (rtx op, enum machine_mode mode) if (CONSTANT_P (op)) return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode || mode == VOIDmode) +#ifdef LEGITIMATE_PIC_OPERAND_P && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) +#endif && LEGITIMATE_CONSTANT_P (op)); /* Except for certain constants with VOIDmode, already checked for, @@ -975,10 +950,8 @@ general_operand (rtx op, enum machine_mode mode) #ifdef INSN_SCHEDULING /* On machines that have insn scheduling, we want all memory - reference to be explicit, so outlaw paradoxical SUBREGs. - However, we must allow them after reload so that they can - get cleaned up by cleanup_subreg_operands. */ - if (!reload_completed && MEM_P (sub) + reference to be explicit, so outlaw paradoxical SUBREGs. */ + if (GET_CODE (sub) == MEM && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (sub))) return 0; #endif @@ -989,12 +962,12 @@ general_operand (rtx op, enum machine_mode mode) ??? This is a kludge. */ if (!reload_completed && SUBREG_BYTE (op) != 0 - && MEM_P (sub)) + && GET_CODE (sub) == MEM) return 0; /* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally create such rtl, and we must reject it. */ - if (SCALAR_FLOAT_MODE_P (GET_MODE (op)) + if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT && GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub))) return 0; @@ -1014,12 +987,23 @@ general_operand (rtx op, enum machine_mode mode) if (! volatile_ok && MEM_VOLATILE_P (op)) return 0; - /* Use the mem's mode, since it will be reloaded thus. */ - if (memory_address_p (GET_MODE (op), y)) + if (GET_CODE (y) == ADDRESSOF) return 1; + + /* Use the mem's mode, since it will be reloaded thus. */ + mode = GET_MODE (op); + GO_IF_LEGITIMATE_ADDRESS (mode, y, win); } + /* Pretend this is an operand for now; we'll run force_operand + on its replacement in fixup_var_refs_1. */ + if (code == ADDRESSOF) + return 1; + return 0; + + win: + return 1; } /* Return 1 if OP is a valid memory address for a memory reference @@ -1064,11 +1048,11 @@ register_operand (rtx op, enum machine_mode mode) (Ideally, (SUBREG (MEM)...) should not exist after reload, but currently it does result from (SUBREG (REG)...) where the reg went on the stack.) */ - if (! reload_completed && MEM_P (sub)) + if (! reload_completed && GET_CODE (sub) == MEM) return general_operand (op, mode); #ifdef CANNOT_CHANGE_MODE_CLASS - if (REG_P (sub) + if (GET_CODE (sub) == REG && REGNO (sub) < FIRST_PSEUDO_REGISTER && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode) && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT @@ -1078,16 +1062,21 @@ register_operand (rtx op, enum machine_mode mode) /* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally create such rtl, and we must reject it. */ - if (SCALAR_FLOAT_MODE_P (GET_MODE (op)) + if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT && GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub))) return 0; op = sub; } + /* If we have an ADDRESSOF, consider it valid since it will be + converted into something that will not be a MEM. */ + if (GET_CODE (op) == ADDRESSOF) + return 1; + /* We don't consider registers whose class is NO_REGS to be a register operand. */ - return (REG_P (op) + return (GET_CODE (op) == REG && (REGNO (op) >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); } @@ -1110,7 +1099,7 @@ scratch_operand (rtx op, enum machine_mode mode) return 0; return (GET_CODE (op) == SCRATCH - || (REG_P (op) + || (GET_CODE (op) == REG && REGNO (op) < FIRST_PSEUDO_REGISTER)); } @@ -1134,10 +1123,18 @@ immediate_operand (rtx op, enum machine_mode mode) && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op)) return 0; + /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and + result in 0/1. It seems a safe assumption that this is + in range for everyone. */ + if (GET_CODE (op) == CONSTANT_P_RTX) + return 1; + return (CONSTANT_P (op) && (GET_MODE (op) == mode || mode == VOIDmode || GET_MODE (op) == VOIDmode) +#ifdef LEGITIMATE_PIC_OPERAND_P && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) +#endif && LEGITIMATE_CONSTANT_P (op)); } @@ -1203,7 +1200,9 @@ nonmemory_operand (rtx op, enum machine_mode mode) return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode || mode == VOIDmode) +#ifdef LEGITIMATE_PIC_OPERAND_P && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) +#endif && LEGITIMATE_CONSTANT_P (op)); } @@ -1218,14 +1217,14 @@ nonmemory_operand (rtx op, enum machine_mode mode) (Ideally, (SUBREG (MEM)...) should not exist after reload, but currently it does result from (SUBREG (REG)...) where the reg went on the stack.) */ - if (! reload_completed && MEM_P (SUBREG_REG (op))) + if (! reload_completed && GET_CODE (SUBREG_REG (op)) == MEM) return general_operand (op, mode); op = SUBREG_REG (op); } /* We don't consider registers whose class is NO_REGS to be a register operand. */ - return (REG_P (op) + return (GET_CODE (op) == REG && (REGNO (op) >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); } @@ -1245,7 +1244,7 @@ push_operand (rtx op, enum machine_mode mode) rounded_size = PUSH_ROUNDING (rounded_size); #endif - if (!MEM_P (op)) + if (GET_CODE (op) != MEM) return 0; if (mode != VOIDmode && GET_MODE (op) != mode) @@ -1285,7 +1284,7 @@ push_operand (rtx op, enum machine_mode mode) int pop_operand (rtx op, enum machine_mode mode) { - if (!MEM_P (op)) + if (GET_CODE (op) != MEM) return 0; if (mode != VOIDmode && GET_MODE (op) != mode) @@ -1304,6 +1303,9 @@ pop_operand (rtx op, enum machine_mode mode) int memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr) { + if (GET_CODE (addr) == ADDRESSOF) + return 1; + GO_IF_LEGITIMATE_ADDRESS (mode, addr, win); return 0; @@ -1325,7 +1327,7 @@ memory_operand (rtx op, enum machine_mode mode) if (! reload_completed) /* Note that no SUBREG is a memory operand before end of reload pass, because (SUBREG (MEM...)) forces reloading into a register. */ - return MEM_P (op) && general_operand (op, mode); + return GET_CODE (op) == MEM && general_operand (op, mode); if (mode != VOIDmode && GET_MODE (op) != mode) return 0; @@ -1334,7 +1336,7 @@ memory_operand (rtx op, enum machine_mode mode) if (GET_CODE (inner) == SUBREG) inner = SUBREG_REG (inner); - return (MEM_P (inner) && general_operand (op, mode)); + return (GET_CODE (inner) == MEM && general_operand (op, mode)); } /* Return 1 if OP is a valid indirect memory reference with mode MODE; @@ -1345,7 +1347,7 @@ indirect_operand (rtx op, enum machine_mode mode) { /* Before reload, a SUBREG isn't in memory (see memory_operand, above). */ if (! reload_completed - && GET_CODE (op) == SUBREG && MEM_P (SUBREG_REG (op))) + && GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == MEM) { int offset = SUBREG_BYTE (op); rtx inner = SUBREG_REG (op); @@ -1365,7 +1367,7 @@ indirect_operand (rtx op, enum machine_mode mode) && general_operand (XEXP (XEXP (inner, 0), 0), Pmode))); } - return (MEM_P (op) + return (GET_CODE (op) == MEM && memory_operand (op, mode) && general_operand (XEXP (op, 0), Pmode)); } @@ -1377,7 +1379,7 @@ int comparison_operator (rtx op, enum machine_mode mode) { return ((mode == VOIDmode || GET_MODE (op) == mode) - && COMPARISON_P (op)); + && GET_RTX_CLASS (GET_CODE (op)) == '<'); } /* If BODY is an insn body that uses ASM_OPERANDS, @@ -1598,7 +1600,7 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs, return template; } -/* Check if an asm_operand matches its constraints. +/* Check if an asm_operand matches it's constraints. Return > 0 if ok, = 0 if bad, < 0 if inconclusive. */ int @@ -1607,7 +1609,8 @@ asm_operand_ok (rtx op, const char *constraint) int result = 0; /* Use constrain_operands after reload. */ - gcc_assert (!reload_completed); + if (reload_completed) + abort (); while (*constraint) { @@ -1665,7 +1668,7 @@ asm_operand_ok (rtx op, const char *constraint) Match any memory and hope things are resolved after reload. */ - if (MEM_P (op) + if (GET_CODE (op) == MEM && (1 || GET_CODE (XEXP (op, 0)) == PRE_DEC || GET_CODE (XEXP (op, 0)) == POST_DEC)) @@ -1673,7 +1676,7 @@ asm_operand_ok (rtx op, const char *constraint) break; case '>': - if (MEM_P (op) + if (GET_CODE (op) == MEM && (1 || GET_CODE (XEXP (op, 0)) == PRE_INC || GET_CODE (XEXP (op, 0)) == POST_INC)) @@ -1707,7 +1710,11 @@ asm_operand_ok (rtx op, const char *constraint) /* Fall through. */ case 'i': - if (CONSTANT_P (op) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))) + if (CONSTANT_P (op) +#ifdef LEGITIMATE_PIC_OPERAND_P + && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) +#endif + ) result = 1; break; @@ -1864,7 +1871,7 @@ find_constant_term_loc (rtx *p) int offsettable_memref_p (rtx op) { - return ((MEM_P (op)) + return ((GET_CODE (op) == MEM) && offsettable_address_p (1, GET_MODE (op), XEXP (op, 0))); } @@ -1874,7 +1881,7 @@ offsettable_memref_p (rtx op) int offsettable_nonstrict_memref_p (rtx op) { - return ((MEM_P (op)) + return ((GET_CODE (op) == MEM) && offsettable_address_p (0, GET_MODE (op), XEXP (op, 0))); } @@ -1933,7 +1940,7 @@ offsettable_address_p (int strictp, enum machine_mode mode, rtx y) return good; } - if (GET_RTX_CLASS (ycode) == RTX_AUTOINC) + if (GET_RTX_CLASS (ycode) == 'a') return 0; /* The offset added here is chosen as the maximum offset that @@ -1982,7 +1989,6 @@ extract_insn_cached (rtx insn) extract_insn (insn); recog_data.insn = insn; } - /* Do cached extract_insn, constrain_operands and complain about failures. Used by insn_attrtab. */ void @@ -1993,7 +1999,6 @@ extract_constrain_insn_cached (rtx insn) && !constrain_operands (reload_completed)) fatal_insn_not_found (insn); } - /* Do cached constrain_operands and complain about failures. */ int constrain_operands_cached (int strict) @@ -2049,7 +2054,8 @@ extract_insn (rtx insn) /* This insn is an `asm' with operands. */ /* expand_asm_operands makes sure there aren't too many operands. */ - gcc_assert (noperands <= MAX_RECOG_OPERANDS); + if (noperands > MAX_RECOG_OPERANDS) + abort (); /* Now get the operand values and constraints out of the insn. */ decode_asm_operands (body, recog_data.operand, @@ -2097,7 +2103,8 @@ extract_insn (rtx insn) : recog_data.constraints[i][0] == '+' ? OP_INOUT : OP_IN); - gcc_assert (recog_data.n_alternatives <= MAX_RECOG_ALTERNATIVES); + if (recog_data.n_alternatives > MAX_RECOG_ALTERNATIVES) + abort (); } /* After calling extract_insn, you can use this function to extract some @@ -2122,7 +2129,7 @@ preprocess_constraints (void) for (j = 0; j < recog_data.n_alternatives; j++) { - op_alt[j].cl = NO_REGS; + op_alt[j].class = NO_REGS; op_alt[j].constraint = p; op_alt[j].matches = -1; op_alt[j].matched = -1; @@ -2197,14 +2204,12 @@ preprocess_constraints (void) case 'p': op_alt[j].is_address = 1; - op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl] - [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; + op_alt[j].class = reg_class_subunion[(int) op_alt[j].class] + [(int) MODE_BASE_REG_CLASS (VOIDmode)]; break; - case 'g': - case 'r': - op_alt[j].cl = - reg_class_subunion[(int) op_alt[j].cl][(int) GENERAL_REGS]; + case 'g': case 'r': + op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) GENERAL_REGS]; break; default: @@ -2216,17 +2221,16 @@ preprocess_constraints (void) if (EXTRA_ADDRESS_CONSTRAINT (c, p)) { op_alt[j].is_address = 1; - op_alt[j].cl + op_alt[j].class = (reg_class_subunion - [(int) op_alt[j].cl] - [(int) base_reg_class (VOIDmode, ADDRESS, - SCRATCH)]); + [(int) op_alt[j].class] + [(int) MODE_BASE_REG_CLASS (VOIDmode)]); break; } - op_alt[j].cl + op_alt[j].class = (reg_class_subunion - [(int) op_alt[j].cl] + [(int) op_alt[j].class] [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]); break; } @@ -2291,7 +2295,6 @@ constrain_operands (int strict) do { - int seen_earlyclobber_at = -1; int opno; int lose = 0; funny_match_index = 0; @@ -2310,12 +2313,12 @@ constrain_operands (int strict) /* A unary operator may be accepted by the predicate, but it is irrelevant for matching constraints. */ - if (UNARY_P (op)) + if (GET_RTX_CLASS (GET_CODE (op)) == '1') op = XEXP (op, 0); if (GET_CODE (op) == SUBREG) { - if (REG_P (SUBREG_REG (op)) + if (GET_CODE (SUBREG_REG (op)) == REG && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER) offset = subreg_regno_offset (REGNO (SUBREG_REG (op)), GET_MODE (SUBREG_REG (op)), @@ -2354,8 +2357,6 @@ constrain_operands (int strict) case '&': earlyclobber[opno] = 1; - if (seen_earlyclobber_at < 0) - seen_earlyclobber_at = opno; break; case '0': case '1': case '2': case '3': case '4': @@ -2385,9 +2386,9 @@ constrain_operands (int strict) /* A unary operator may be accepted by the predicate, but it is irrelevant for matching constraints. */ - if (UNARY_P (op1)) + if (GET_RTX_CLASS (GET_CODE (op1)) == '1') op1 = XEXP (op1, 0); - if (UNARY_P (op2)) + if (GET_RTX_CLASS (GET_CODE (op2)) == '1') op2 = XEXP (op2, 0); val = operands_match_p (op1, op2); @@ -2423,22 +2424,16 @@ constrain_operands (int strict) break; /* No need to check general_operand again; - it was done in insn-recog.c. Well, except that reload - doesn't check the validity of its replacements, but - that should only matter when there's a bug. */ + it was done in insn-recog.c. */ case 'g': /* Anything goes unless it is a REG and really has a hard reg but the hard reg is not in the class GENERAL_REGS. */ - if (REG_P (op)) - { - if (strict < 0 - || GENERAL_REGS == ALL_REGS - || (reload_in_progress - && REGNO (op) >= FIRST_PSEUDO_REGISTER) - || reg_fits_class_p (op, GENERAL_REGS, offset, mode)) - win = 1; - } - else if (strict < 0 || general_operand (op, mode)) + if (strict < 0 + || GENERAL_REGS == ALL_REGS + || GET_CODE (op) != REG + || (reload_in_progress + && REGNO (op) >= FIRST_PSEUDO_REGISTER) + || reg_fits_class_p (op, GENERAL_REGS, offset, mode)) win = 1; break; @@ -2452,7 +2447,7 @@ constrain_operands (int strict) case 'm': /* Memory operands must be valid, to the extent required by STRICT. */ - if (MEM_P (op)) + if (GET_CODE (op) == MEM) { if (strict > 0 && !strict_memory_address_p (GET_MODE (op), @@ -2467,20 +2462,20 @@ constrain_operands (int strict) else if (strict < 0 && CONSTANT_P (op)) win = 1; /* During reload, accept a pseudo */ - else if (reload_in_progress && REG_P (op) + else if (reload_in_progress && GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) win = 1; break; case '<': - if (MEM_P (op) + if (GET_CODE (op) == MEM && (GET_CODE (XEXP (op, 0)) == PRE_DEC || GET_CODE (XEXP (op, 0)) == POST_DEC)) win = 1; break; case '>': - if (MEM_P (op) + if (GET_CODE (op) == MEM && (GET_CODE (XEXP (op, 0)) == PRE_INC || GET_CODE (XEXP (op, 0)) == POST_INC)) win = 1; @@ -2532,12 +2527,12 @@ constrain_operands (int strict) break; case 'V': - if (MEM_P (op) + if (GET_CODE (op) == MEM && ((strict > 0 && ! offsettable_memref_p (op)) || (strict < 0 - && !(CONSTANT_P (op) || MEM_P (op))) + && !(CONSTANT_P (op) || GET_CODE (op) == MEM)) || (reload_in_progress - && !(REG_P (op) + && !(GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)))) win = 1; break; @@ -2547,28 +2542,28 @@ constrain_operands (int strict) || (strict == 0 && offsettable_nonstrict_memref_p (op)) /* Before reload, accept what reload can handle. */ || (strict < 0 - && (CONSTANT_P (op) || MEM_P (op))) + && (CONSTANT_P (op) || GET_CODE (op) == MEM)) /* During reload, accept a pseudo */ - || (reload_in_progress && REG_P (op) + || (reload_in_progress && GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)) win = 1; break; default: { - enum reg_class cl; + enum reg_class class; - cl = (c == 'r' + class = (c == 'r' ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p)); - if (cl != NO_REGS) + if (class != NO_REGS) { if (strict < 0 || (strict == 0 - && REG_P (op) + && GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) || (strict == 0 && GET_CODE (op) == SCRATCH) - || (REG_P (op) - && reg_fits_class_p (op, cl, offset, mode))) + || (GET_CODE (op) == REG + && reg_fits_class_p (op, class, offset, mode))) win = 1; } #ifdef EXTRA_CONSTRAINT_STR @@ -2577,12 +2572,12 @@ constrain_operands (int strict) else if (EXTRA_MEMORY_CONSTRAINT (c, p) /* Every memory operand can be reloaded to fit. */ - && ((strict < 0 && MEM_P (op)) + && ((strict < 0 && GET_CODE (op) == MEM) /* Before reload, accept what reload can turn into mem. */ || (strict < 0 && CONSTANT_P (op)) /* During reload, accept a pseudo */ - || (reload_in_progress && REG_P (op) + || (reload_in_progress && GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER))) win = 1; else if (EXTRA_ADDRESS_CONSTRAINT (c, p) @@ -2610,17 +2605,15 @@ constrain_operands (int strict) /* See if any earlyclobber operand conflicts with some other operand. */ - if (strict > 0 && seen_earlyclobber_at >= 0) - for (eopno = seen_earlyclobber_at; - eopno < recog_data.n_operands; - eopno++) + if (strict > 0) + for (eopno = 0; eopno < recog_data.n_operands; eopno++) /* Ignore earlyclobber operands now in memory, because we would often report failure when we have two memory operands, one of which was formerly a REG. */ if (earlyclobber[eopno] - && REG_P (recog_data.operand[eopno])) + && GET_CODE (recog_data.operand[eopno]) == REG) for (opno = 0; opno < recog_data.n_operands; opno++) - if ((MEM_P (recog_data.operand[opno]) + if ((GET_CODE (recog_data.operand[opno]) == MEM || recog_data.operand_type[opno] != OP_OUT) && opno != eopno /* Ignore things like match_operator operands. */ @@ -2663,23 +2656,19 @@ constrain_operands (int strict) If REG occupies multiple hard regs, all of them must be in CLASS. */ int -reg_fits_class_p (rtx operand, enum reg_class cl, int offset, +reg_fits_class_p (rtx operand, enum reg_class class, int offset, enum machine_mode mode) { int regno = REGNO (operand); - - if (cl == NO_REGS) - return 0; - if (regno < FIRST_PSEUDO_REGISTER - && TEST_HARD_REG_BIT (reg_class_contents[(int) cl], + && TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno + offset)) { int sr; regno += offset; - for (sr = hard_regno_nregs[regno][mode] - 1; + for (sr = HARD_REGNO_NREGS (regno, mode) - 1; sr > 0; sr--) - if (! TEST_HARD_REG_BIT (reg_class_contents[(int) cl], + if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno + sr)) break; return sr == 0; @@ -2703,7 +2692,9 @@ split_insn (rtx insn) return NULL_RTX; /* try_split returns the NOTE that INSN became. */ - SET_INSN_DELETED (insn); + PUT_CODE (insn, NOTE); + NOTE_SOURCE_FILE (insn) = 0; + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; /* ??? Coddle to md files that generate subregs in post-reload splitters instead of computing the proper hard register. */ @@ -2782,7 +2773,7 @@ split_all_insns (int upd_life) BB boundary we are interested in will be set to previous one. */ - while (BARRIER_P (last)) + while (GET_CODE (last) == BARRIER) last = PREV_INSN (last); SET_BIT (blocks, bb->index); changed = true; @@ -2804,7 +2795,7 @@ split_all_insns (int upd_life) if (changed && upd_life) update_life_info (blocks, UPDATE_LIFE_GLOBAL_RM_NOTES, - PROP_DEATH_NOTES); + PROP_DEATH_NOTES | PROP_REG_INFO); #ifdef ENABLE_CHECKING verify_flow_info (); @@ -2816,7 +2807,7 @@ split_all_insns (int upd_life) /* Same as split_all_insns, but do not expect CFG to be available. Used by machine dependent reorg passes. */ -unsigned int +void split_all_insns_noflow (void) { rtx next, insn; @@ -2846,7 +2837,6 @@ split_all_insns_noflow (void) split_insn (insn); } } - return 0; } #ifdef HAVE_peephole2 @@ -2858,8 +2848,6 @@ struct peep2_insn_data static struct peep2_insn_data peep2_insn_data[MAX_INSNS_PER_PEEP2 + 1]; static int peep2_current; -/* The number of instructions available to match a peep2. */ -int peep2_current_count; /* A non-insn marker indicating the last insn of the block. The live_before regset for this element is correct, indicating @@ -2873,12 +2861,15 @@ int peep2_current_count; rtx peep2_next_insn (int n) { - gcc_assert (n <= peep2_current_count); + if (n >= MAX_INSNS_PER_PEEP2 + 1) + abort (); n += peep2_current; if (n >= MAX_INSNS_PER_PEEP2 + 1) n -= MAX_INSNS_PER_PEEP2 + 1; + if (peep2_insn_data[n].insn == PEEP2_EOB) + return NULL_RTX; return peep2_insn_data[n].insn; } @@ -2888,13 +2879,15 @@ peep2_next_insn (int n) int peep2_regno_dead_p (int ofs, int regno) { - gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1); + if (ofs >= MAX_INSNS_PER_PEEP2 + 1) + abort (); ofs += peep2_current; if (ofs >= MAX_INSNS_PER_PEEP2 + 1) ofs -= MAX_INSNS_PER_PEEP2 + 1; - gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX); + if (peep2_insn_data[ofs].insn == NULL_RTX) + abort (); return ! REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno); } @@ -2906,16 +2899,18 @@ peep2_reg_dead_p (int ofs, rtx reg) { int regno, n; - gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1); + if (ofs >= MAX_INSNS_PER_PEEP2 + 1) + abort (); ofs += peep2_current; if (ofs >= MAX_INSNS_PER_PEEP2 + 1) ofs -= MAX_INSNS_PER_PEEP2 + 1; - gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX); + if (peep2_insn_data[ofs].insn == NULL_RTX) + abort (); regno = REGNO (reg); - n = hard_regno_nregs[regno][GET_MODE (reg)]; + n = HARD_REGNO_NREGS (regno, GET_MODE (reg)); while (--n >= 0) if (REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno + n)) return 0; @@ -2938,12 +2933,12 @@ peep2_find_free_register (int from, int to, const char *class_str, enum machine_mode mode, HARD_REG_SET *reg_set) { static int search_ofs; - enum reg_class cl; + enum reg_class class; HARD_REG_SET live; int i; - gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1); - gcc_assert (to < MAX_INSNS_PER_PEEP2 + 1); + if (from >= MAX_INSNS_PER_PEEP2 + 1 || to >= MAX_INSNS_PER_PEEP2 + 1) + abort (); from += peep2_current; if (from >= MAX_INSNS_PER_PEEP2 + 1) @@ -2952,7 +2947,8 @@ peep2_find_free_register (int from, int to, const char *class_str, if (to >= MAX_INSNS_PER_PEEP2 + 1) to -= MAX_INSNS_PER_PEEP2 + 1; - gcc_assert (peep2_insn_data[from].insn != NULL_RTX); + if (peep2_insn_data[from].insn == NULL_RTX) + abort (); REG_SET_TO_HARD_REG_SET (live, peep2_insn_data[from].live_before); while (from != to) @@ -2961,12 +2957,13 @@ peep2_find_free_register (int from, int to, const char *class_str, if (++from >= MAX_INSNS_PER_PEEP2 + 1) from = 0; - gcc_assert (peep2_insn_data[from].insn != NULL_RTX); + if (peep2_insn_data[from].insn == NULL_RTX) + abort (); REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before); IOR_HARD_REG_SET (live, this_live); } - cl = (class_str[0] == 'r' ? GENERAL_REGS + class = (class_str[0] == 'r' ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (class_str[0], class_str)); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) @@ -2987,7 +2984,7 @@ peep2_find_free_register (int from, int to, const char *class_str, if (fixed_regs[regno]) continue; /* Make sure the register is of the right class. */ - if (! TEST_HARD_REG_BIT (reg_class_contents[cl], regno)) + if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno)) continue; /* And can support the mode we need. */ if (! HARD_REGNO_MODE_OK (regno, mode)) @@ -3001,7 +2998,7 @@ peep2_find_free_register (int from, int to, const char *class_str, continue; success = 1; - for (j = hard_regno_nregs[regno][mode] - 1; j >= 0; j--) + for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--) { if (TEST_HARD_REG_BIT (*reg_set, regno + j) || TEST_HARD_REG_BIT (live, regno + j)) @@ -3012,7 +3009,7 @@ peep2_find_free_register (int from, int to, const char *class_str, } if (success) { - for (j = hard_regno_nregs[regno][mode] - 1; j >= 0; j--) + for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--) SET_HARD_REG_BIT (*reg_set, regno + j); /* Start the next search with the next register. */ @@ -3030,9 +3027,10 @@ peep2_find_free_register (int from, int to, const char *class_str, /* Perform the peephole2 optimization pass. */ -static void -peephole2_optimize (void) +void +peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) { + regset_head rs_heads[MAX_INSNS_PER_PEEP2 + 2]; rtx insn, prev; regset live; int i; @@ -3042,13 +3040,12 @@ peephole2_optimize (void) bool changed; #endif bool do_cleanup_cfg = false; - bool do_global_life_update = false; bool do_rebuild_jump_labels = false; /* Initialize the regsets we're going to use. */ for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i) - peep2_insn_data[i].live_before = ALLOC_REG_SET (®_obstack); - live = ALLOC_REG_SET (®_obstack); + peep2_insn_data[i].live_before = INITIALIZE_REG_SET (rs_heads[i]); + live = INITIALIZE_REG_SET (rs_heads[i]); #ifdef HAVE_conditional_execution blocks = sbitmap_alloc (last_basic_block); @@ -3061,20 +3058,17 @@ peephole2_optimize (void) FOR_EACH_BB_REVERSE (bb) { struct propagate_block_info *pbi; - reg_set_iterator rsi; - unsigned int j; /* Indicate that all slots except the last holds invalid data. */ for (i = 0; i < MAX_INSNS_PER_PEEP2; ++i) peep2_insn_data[i].insn = NULL_RTX; - peep2_current_count = 0; /* Indicate that the last slot contains live_after data. */ peep2_insn_data[MAX_INSNS_PER_PEEP2].insn = PEEP2_EOB; peep2_current = MAX_INSNS_PER_PEEP2; /* Start up propagation. */ - COPY_REG_SET (live, bb->il.rtl->global_live_at_end); + COPY_REG_SET (live, bb->global_live_at_end); COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live); #ifdef HAVE_conditional_execution @@ -3096,25 +3090,12 @@ peephole2_optimize (void) /* Record this insn. */ if (--peep2_current < 0) peep2_current = MAX_INSNS_PER_PEEP2; - if (peep2_current_count < MAX_INSNS_PER_PEEP2 - && peep2_insn_data[peep2_current].insn == NULL_RTX) - peep2_current_count++; peep2_insn_data[peep2_current].insn = insn; propagate_one_insn (pbi, insn); COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live); - if (RTX_FRAME_RELATED_P (insn)) - { - /* If an insn has RTX_FRAME_RELATED_P set, peephole - substitution would lose the - REG_FRAME_RELATED_EXPR that is attached. */ - peep2_current_count = 0; - try = NULL; - } - else - /* Match the peephole. */ - try = peephole2_insns (PATTERN (insn), insn, &match_len); - + /* Match the peephole. */ + try = peephole2_insns (PATTERN (insn), insn, &match_len); if (try != NULL) { /* If we are splitting a CALL_INSN, look for the CALL_INSN @@ -3129,19 +3110,20 @@ peephole2_optimize (void) if (j >= MAX_INSNS_PER_PEEP2 + 1) j -= MAX_INSNS_PER_PEEP2 + 1; old_insn = peep2_insn_data[j].insn; - if (!CALL_P (old_insn)) + if (GET_CODE (old_insn) != CALL_INSN) continue; was_call = true; new_insn = try; while (new_insn != NULL_RTX) { - if (CALL_P (new_insn)) + if (GET_CODE (new_insn) == CALL_INSN) break; new_insn = NEXT_INSN (new_insn); } - gcc_assert (new_insn != NULL_RTX); + if (new_insn == NULL_RTX) + abort (); CALL_INSN_FUNCTION_USAGE (new_insn) = CALL_INSN_FUNCTION_USAGE (old_insn); @@ -3153,6 +3135,7 @@ peephole2_optimize (void) { case REG_NORETURN: case REG_SETJMP: + case REG_ALWAYS_RETURN: REG_NOTES (new_insn) = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note), XEXP (note, 0), @@ -3169,7 +3152,8 @@ peephole2_optimize (void) if (j >= MAX_INSNS_PER_PEEP2 + 1) j -= MAX_INSNS_PER_PEEP2 + 1; old_insn = peep2_insn_data[j].insn; - gcc_assert (!CALL_P (old_insn)); + if (GET_CODE (old_insn) == CALL_INSN) + abort (); } break; } @@ -3191,14 +3175,14 @@ peephole2_optimize (void) if (note || (was_call && nonlocal_goto_handler_labels)) { edge eh_edge; - edge_iterator ei; - FOR_EACH_EDGE (eh_edge, ei, bb->succs) + for (eh_edge = bb->succ; eh_edge + ; eh_edge = eh_edge->succ_next) if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) break; for (x = try ; x != before_try ; x = PREV_INSN (x)) - if (CALL_P (x) + if (GET_CODE (x) == CALL_INSN || (flag_non_call_exceptions && may_trap_p (PATTERN (x)) && !find_reg_note (x, REG_EH_REGION, NULL))) @@ -3217,7 +3201,7 @@ peephole2_optimize (void) nfte = split_block (bb, x); flags = (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL)); - if (CALL_P (x)) + if (GET_CODE (x) == CALL_INSN) flags |= EDGE_ABNORMAL_CALL; nehe = make_edge (nfte->src, eh_edge->dest, flags); @@ -3253,7 +3237,6 @@ peephole2_optimize (void) for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i) peep2_insn_data[i].insn = NULL_RTX; peep2_insn_data[peep2_current].insn = PEEP2_EOB; - peep2_current_count = 0; #else /* Back up lifetime information past the end of the newly created sequence. */ @@ -3269,9 +3252,6 @@ peephole2_optimize (void) { if (--i < 0) i = MAX_INSNS_PER_PEEP2; - if (peep2_current_count < MAX_INSNS_PER_PEEP2 - && peep2_insn_data[i].insn == NULL_RTX) - peep2_current_count++; peep2_insn_data[i].insn = x; propagate_one_insn (pbi, x); COPY_REG_SET (peep2_insn_data[i].live_before, live); @@ -3289,7 +3269,7 @@ peephole2_optimize (void) /* If we generated a jump instruction, it won't have JUMP_LABEL set. Recompute after we're done. */ for (x = try; x != before_try; x = PREV_INSN (x)) - if (JUMP_P (x)) + if (GET_CODE (x) == JUMP_INSN) { do_rebuild_jump_labels = true; break; @@ -3301,15 +3281,6 @@ peephole2_optimize (void) break; } - /* Some peepholes can decide the don't need one or more of their - inputs. If this happens, local life update is not enough. */ - EXECUTE_IF_AND_COMPL_IN_BITMAP (bb->il.rtl->global_live_at_start, live, - 0, j, rsi) - { - do_global_life_update = true; - break; - } - free_propagate_block_info (pbi); } @@ -3326,10 +3297,8 @@ peephole2_optimize (void) if (do_cleanup_cfg) { cleanup_cfg (0); - do_global_life_update = true; + update_life_info (0, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES); } - if (do_global_life_update) - update_life_info (0, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES); #ifdef HAVE_conditional_execution else { @@ -3354,9 +3323,10 @@ store_data_bypass_p (rtx out_insn, rtx in_insn) rtx out_set, in_set; in_set = single_set (in_insn); - gcc_assert (in_set); + if (! in_set) + abort (); - if (!MEM_P (SET_DEST (in_set))) + if (GET_CODE (SET_DEST (in_set)) != MEM) return false; out_set = single_set (out_insn); @@ -3371,7 +3341,8 @@ store_data_bypass_p (rtx out_insn, rtx in_insn) int i; out_pat = PATTERN (out_insn); - gcc_assert (GET_CODE (out_pat) == PARALLEL); + if (GET_CODE (out_pat) != PARALLEL) + abort (); for (i = 0; i < XVECLEN (out_pat, 0); i++) { @@ -3380,7 +3351,8 @@ store_data_bypass_p (rtx out_insn, rtx in_insn) if (GET_CODE (exp) == CLOBBER) continue; - gcc_assert (GET_CODE (exp) == SET); + if (GET_CODE (exp) != SET) + abort (); if (reg_mentioned_p (SET_DEST (exp), SET_DEST (in_set))) return false; @@ -3403,8 +3375,9 @@ if_test_bypass_p (rtx out_insn, rtx in_insn) in_set = single_set (in_insn); if (! in_set) { - gcc_assert (JUMP_P (in_insn) || CALL_P (in_insn)); - return false; + if (GET_CODE (in_insn) == JUMP_INSN || GET_CODE (in_insn) == CALL_INSN) + return false; + abort (); } if (GET_CODE (SET_SRC (in_set)) != IF_THEN_ELSE) @@ -3424,7 +3397,8 @@ if_test_bypass_p (rtx out_insn, rtx in_insn) int i; out_pat = PATTERN (out_insn); - gcc_assert (GET_CODE (out_pat) == PARALLEL); + if (GET_CODE (out_pat) != PARALLEL) + abort (); for (i = 0; i < XVECLEN (out_pat, 0); i++) { @@ -3433,7 +3407,8 @@ if_test_bypass_p (rtx out_insn, rtx in_insn) if (GET_CODE (exp) == CLOBBER) continue; - gcc_assert (GET_CODE (exp) == SET); + if (GET_CODE (exp) != SET) + abort (); if (reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 1)) || reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 2))) @@ -3443,124 +3418,3 @@ if_test_bypass_p (rtx out_insn, rtx in_insn) return true; } - -static bool -gate_handle_peephole2 (void) -{ - return (optimize > 0 && flag_peephole2); -} - -static unsigned int -rest_of_handle_peephole2 (void) -{ -#ifdef HAVE_peephole2 - peephole2_optimize (); -#endif - return 0; -} - -struct tree_opt_pass pass_peephole2 = -{ - "peephole2", /* name */ - gate_handle_peephole2, /* gate */ - rest_of_handle_peephole2, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_PEEPHOLE2, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 'z' /* letter */ -}; - -static unsigned int -rest_of_handle_split_all_insns (void) -{ - split_all_insns (1); - return 0; -} - -struct tree_opt_pass pass_split_all_insns = -{ - "split1", /* name */ - NULL, /* gate */ - rest_of_handle_split_all_insns, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - 0, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ -}; - -/* The placement of the splitting that we do for shorten_branches - depends on whether regstack is used by the target or not. */ -static bool -gate_do_final_split (void) -{ -#if defined (HAVE_ATTR_length) && !defined (STACK_REGS) - return 1; -#else - return 0; -#endif -} - -struct tree_opt_pass pass_split_for_shorten_branches = -{ - "split3", /* name */ - gate_do_final_split, /* gate */ - split_all_insns_noflow, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_SHORTEN_BRANCH, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ -}; - - -static bool -gate_handle_split_before_regstack (void) -{ -#if defined (HAVE_ATTR_length) && defined (STACK_REGS) - /* If flow2 creates new instructions which need splitting - and scheduling after reload is not done, they might not be - split until final which doesn't allow splitting - if HAVE_ATTR_length. */ -# ifdef INSN_SCHEDULING - return (optimize && !flag_schedule_insns_after_reload); -# else - return (optimize); -# endif -#else - return 0; -#endif -} - -struct tree_opt_pass pass_split_before_regstack = -{ - "split2", /* name */ - gate_handle_split_before_regstack, /* gate */ - rest_of_handle_split_all_insns, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_SHORTEN_BRANCH, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ -}; diff --git a/contrib/gcc/reload.c b/contrib/gcc/reload.c index 08a393f..9eae9ff 100644 --- a/contrib/gcc/reload.c +++ b/contrib/gcc/reload.c @@ -1,7 +1,6 @@ /* Search an insn for pseudo regs that must be in hard regs and are not. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, - Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -17,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ /* This file contains subroutines used only from the file reload1.c. It knows how to scan one insn for operands and values @@ -28,7 +27,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ought to be used instead. Before processing the first insn of the function, call `init_reload'. - init_reload actually has to be called earlier anyway. To scan an insn, call `find_reloads'. This does two things: 1. sets up tables describing which values must be reloaded @@ -100,7 +98,6 @@ a register with any other reload. */ #include "recog.h" #include "reload.h" #include "regs.h" -#include "addresses.h" #include "hard-reg-set.h" #include "flags.h" #include "real.h" @@ -108,20 +105,14 @@ a register with any other reload. */ #include "function.h" #include "toplev.h" #include "params.h" -#include "target.h" -/* True if X is a constant that can be forced into the constant pool. */ -#define CONST_POOL_OK_P(X) \ - (CONSTANT_P (X) \ - && GET_CODE (X) != HIGH \ - && !targetm.cannot_force_const_mem (X)) - -/* True if C is a non-empty register class that has too few registers - to be safely used as a reload target class. */ -#define SMALL_REGISTER_CLASS_P(C) \ - (reg_class_size [(C)] == 1 \ - || (reg_class_size [(C)] >= 1 && CLASS_LIKELY_SPILLED_P (C))) +#ifndef REGNO_MODE_OK_FOR_BASE_P +#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) REGNO_OK_FOR_BASE_P (REGNO) +#endif +#ifndef REG_MODE_OK_FOR_BASE_P +#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO) +#endif /* All reloads of the current insn are recorded here. See reload.h for comments. */ @@ -212,8 +203,8 @@ static int output_reloadnum; /* Compare two RTX's. */ #define MATCHES(x, y) \ - (x == y || (x != 0 && (REG_P (x) \ - ? REG_P (y) && REGNO (x) == REGNO (y) \ + (x == y || (x != 0 && (GET_CODE (x) == REG \ + ? GET_CODE (y) == REG && REGNO (x) == REGNO (y) \ : rtx_equal_p (x, y) && ! side_effects_p (x)))) /* Indicates if two reloads purposes are for similar enough things that we @@ -244,11 +235,12 @@ static int output_reloadnum; ? RELOAD_FOR_OUTADDR_ADDRESS \ : (type))) +#ifdef HAVE_SECONDARY_RELOADS static int push_secondary_reload (int, rtx, int, int, enum reg_class, enum machine_mode, enum reload_type, - enum insn_code *, secondary_reload_info *); -static enum reg_class find_valid_class (enum machine_mode, enum machine_mode, - int, unsigned int); + enum insn_code *); +#endif +static enum reg_class find_valid_class (enum machine_mode, int, unsigned int); static int reload_inner_reg_of_subreg (rtx, enum machine_mode, int); static void push_replacement (rtx *, int, enum machine_mode); static void dup_replacements (rtx *, rtx *); @@ -270,8 +262,7 @@ static int find_reloads_address (enum machine_mode, rtx *, rtx, rtx *, static rtx subst_reg_equivs (rtx, rtx); static rtx subst_indexed_address (rtx); static void update_auto_inc_notes (rtx, int, int); -static int find_reloads_address_1 (enum machine_mode, rtx, int, - enum rtx_code, enum rtx_code, rtx *, +static int find_reloads_address_1 (enum machine_mode, rtx, int, rtx *, int, enum reload_type,int, rtx); static void find_reloads_address_part (rtx, rtx *, enum reg_class, enum machine_mode, int, @@ -280,27 +271,9 @@ static rtx find_reloads_subreg_address (rtx, int, int, enum reload_type, int, rtx); static void copy_replacements_1 (rtx *, rtx *, int); static int find_inc_amount (rtx, rtx); -static int refers_to_mem_for_reload_p (rtx); -static int refers_to_regno_for_reload_p (unsigned int, unsigned int, - rtx, rtx *); - -/* Add NEW to reg_equiv_alt_mem_list[REGNO] if it's not present in the - list yet. */ - -static void -push_reg_equiv_alt_mem (int regno, rtx mem) -{ - rtx it; - - for (it = reg_equiv_alt_mem_list [regno]; it; it = XEXP (it, 1)) - if (rtx_equal_p (XEXP (it, 0), mem)) - return; - - reg_equiv_alt_mem_list [regno] - = alloc_EXPR_LIST (REG_EQUIV, mem, - reg_equiv_alt_mem_list [regno]); -} +#ifdef HAVE_SECONDARY_RELOADS + /* Determine if any secondary reloads are needed for loading (if IN_P is nonzero) or storing (if IN_P is zero) X to or from a reload register of register class RELOAD_CLASS in mode RELOAD_MODE. If secondary reloads @@ -314,18 +287,16 @@ static int push_secondary_reload (int in_p, rtx x, int opnum, int optional, enum reg_class reload_class, enum machine_mode reload_mode, enum reload_type type, - enum insn_code *picode, secondary_reload_info *prev_sri) + enum insn_code *picode) { enum reg_class class = NO_REGS; - enum reg_class scratch_class; enum machine_mode mode = reload_mode; enum insn_code icode = CODE_FOR_nothing; + enum reg_class t_class = NO_REGS; + enum machine_mode t_mode = VOIDmode; enum insn_code t_icode = CODE_FOR_nothing; enum reload_type secondary_type; int s_reload, t_reload = -1; - const char *scratch_constraint; - char letter; - secondary_reload_info sri; if (type == RELOAD_FOR_INPUT_ADDRESS || type == RELOAD_FOR_OUTPUT_ADDRESS @@ -353,25 +324,40 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional, a secondary reload is needed since whether or not a reload is needed might be sensitive to the form of the MEM. */ - if (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER + if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER && reg_equiv_mem[REGNO (x)] != 0) x = reg_equiv_mem[REGNO (x)]; - sri.icode = CODE_FOR_nothing; - sri.prev_sri = prev_sri; - class = targetm.secondary_reload (in_p, x, reload_class, reload_mode, &sri); - icode = sri.icode; +#ifdef SECONDARY_INPUT_RELOAD_CLASS + if (in_p) + class = SECONDARY_INPUT_RELOAD_CLASS (reload_class, reload_mode, x); +#endif + +#ifdef SECONDARY_OUTPUT_RELOAD_CLASS + if (! in_p) + class = SECONDARY_OUTPUT_RELOAD_CLASS (reload_class, reload_mode, x); +#endif /* If we don't need any secondary registers, done. */ - if (class == NO_REGS && icode == CODE_FOR_nothing) + if (class == NO_REGS) return -1; - if (class != NO_REGS) - t_reload = push_secondary_reload (in_p, x, opnum, optional, class, - reload_mode, type, &t_icode, &sri); + /* Get a possible insn to use. If the predicate doesn't accept X, don't + use the insn. */ + + icode = (in_p ? reload_in_optab[(int) reload_mode] + : reload_out_optab[(int) reload_mode]); + + if (icode != CODE_FOR_nothing + && insn_data[(int) icode].operand[in_p].predicate + && (! (insn_data[(int) icode].operand[in_p].predicate) (x, reload_mode))) + icode = CODE_FOR_nothing; - /* If we will be using an insn, the secondary reload is for a - scratch register. */ + /* If we will be using an insn, see if it can directly handle the reload + register we will be using. If it can, the secondary reload is for a + scratch register. If it can't, we will use the secondary reload for + an intermediate register and require a tertiary reload for the scratch + register. */ if (icode != CODE_FOR_nothing) { @@ -380,29 +366,47 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional, in operand 1. Outputs should have an initial "=", which we must skip. */ - /* ??? It would be useful to be able to handle only two, or more than - three, operands, but for now we can only handle the case of having - exactly three: output, input and one temp/scratch. */ - gcc_assert (insn_data[(int) icode].n_operands == 3); - - /* ??? We currently have no way to represent a reload that needs - an icode to reload from an intermediate tertiary reload register. - We should probably have a new field in struct reload to tag a - chain of scratch operand reloads onto. */ - gcc_assert (class == NO_REGS); - - scratch_constraint = insn_data[(int) icode].operand[2].constraint; - gcc_assert (*scratch_constraint == '='); - scratch_constraint++; - if (*scratch_constraint == '&') - scratch_constraint++; - letter = *scratch_constraint; - scratch_class = (letter == 'r' ? GENERAL_REGS - : REG_CLASS_FROM_CONSTRAINT ((unsigned char) letter, - scratch_constraint)); - - class = scratch_class; - mode = insn_data[(int) icode].operand[2].mode; + enum reg_class insn_class; + + if (insn_data[(int) icode].operand[!in_p].constraint[0] == 0) + insn_class = ALL_REGS; + else + { + const char *insn_constraint + = &insn_data[(int) icode].operand[!in_p].constraint[in_p]; + char insn_letter = *insn_constraint; + insn_class + = (insn_letter == 'r' ? GENERAL_REGS + : REG_CLASS_FROM_CONSTRAINT ((unsigned char) insn_letter, + insn_constraint)); + + if (insn_class == NO_REGS) + abort (); + if (in_p + && insn_data[(int) icode].operand[!in_p].constraint[0] != '=') + abort (); + } + + /* The scratch register's constraint must start with "=&". */ + if (insn_data[(int) icode].operand[2].constraint[0] != '=' + || insn_data[(int) icode].operand[2].constraint[1] != '&') + abort (); + + if (reg_class_subset_p (reload_class, insn_class)) + mode = insn_data[(int) icode].operand[2].mode; + else + { + const char *t_constraint + = &insn_data[(int) icode].operand[2].constraint[2]; + char t_letter = *t_constraint; + class = insn_class; + t_mode = insn_data[(int) icode].operand[2].mode; + t_class = (t_letter == 'r' ? GENERAL_REGS + : REG_CLASS_FROM_CONSTRAINT ((unsigned char) t_letter, + t_constraint)); + t_icode = icode; + icode = CODE_FOR_nothing; + } } /* This case isn't valid, so fail. Reload is allowed to use the same @@ -419,8 +423,71 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional, Allow this when a reload_in/out pattern is being used. I.e. assume that the generated code handles this case. */ - gcc_assert (!in_p || class != reload_class || icode != CODE_FOR_nothing - || t_icode != CODE_FOR_nothing); + if (in_p && class == reload_class && icode == CODE_FOR_nothing + && t_icode == CODE_FOR_nothing) + abort (); + + /* If we need a tertiary reload, see if we have one we can reuse or else + make a new one. */ + + if (t_class != NO_REGS) + { + for (t_reload = 0; t_reload < n_reloads; t_reload++) + if (rld[t_reload].secondary_p + && (reg_class_subset_p (t_class, rld[t_reload].class) + || reg_class_subset_p (rld[t_reload].class, t_class)) + && ((in_p && rld[t_reload].inmode == t_mode) + || (! in_p && rld[t_reload].outmode == t_mode)) + && ((in_p && (rld[t_reload].secondary_in_icode + == CODE_FOR_nothing)) + || (! in_p &&(rld[t_reload].secondary_out_icode + == CODE_FOR_nothing))) + && (reg_class_size[(int) t_class] == 1 || SMALL_REGISTER_CLASSES) + && MERGABLE_RELOADS (secondary_type, + rld[t_reload].when_needed, + opnum, rld[t_reload].opnum)) + { + if (in_p) + rld[t_reload].inmode = t_mode; + if (! in_p) + rld[t_reload].outmode = t_mode; + + if (reg_class_subset_p (t_class, rld[t_reload].class)) + rld[t_reload].class = t_class; + + rld[t_reload].opnum = MIN (rld[t_reload].opnum, opnum); + rld[t_reload].optional &= optional; + rld[t_reload].secondary_p = 1; + if (MERGE_TO_OTHER (secondary_type, rld[t_reload].when_needed, + opnum, rld[t_reload].opnum)) + rld[t_reload].when_needed = RELOAD_OTHER; + } + + if (t_reload == n_reloads) + { + /* We need to make a new tertiary reload for this register class. */ + rld[t_reload].in = rld[t_reload].out = 0; + rld[t_reload].class = t_class; + rld[t_reload].inmode = in_p ? t_mode : VOIDmode; + rld[t_reload].outmode = ! in_p ? t_mode : VOIDmode; + rld[t_reload].reg_rtx = 0; + rld[t_reload].optional = optional; + rld[t_reload].inc = 0; + /* Maybe we could combine these, but it seems too tricky. */ + rld[t_reload].nocombine = 1; + rld[t_reload].in_reg = 0; + rld[t_reload].out_reg = 0; + rld[t_reload].opnum = opnum; + rld[t_reload].when_needed = secondary_type; + rld[t_reload].secondary_in_reload = -1; + rld[t_reload].secondary_out_reload = -1; + rld[t_reload].secondary_in_icode = CODE_FOR_nothing; + rld[t_reload].secondary_out_icode = CODE_FOR_nothing; + rld[t_reload].secondary_p = 1; + + n_reloads++; + } + } /* See if we can reuse an existing secondary reload. */ for (s_reload = 0; s_reload < n_reloads; s_reload++) @@ -433,7 +500,7 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional, || (! in_p && rld[s_reload].secondary_out_reload == t_reload)) && ((in_p && rld[s_reload].secondary_in_icode == t_icode) || (! in_p && rld[s_reload].secondary_out_icode == t_icode)) - && (SMALL_REGISTER_CLASS_P (class) || SMALL_REGISTER_CLASSES) + && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES) && MERGABLE_RELOADS (secondary_type, rld[s_reload].when_needed, opnum, rld[s_reload].opnum)) { @@ -506,58 +573,7 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional, *picode = icode; return s_reload; } - -/* If a secondary reload is needed, return its class. If both an intermediate - register and a scratch register is needed, we return the class of the - intermediate register. */ -enum reg_class -secondary_reload_class (bool in_p, enum reg_class class, - enum machine_mode mode, rtx x) -{ - enum insn_code icode; - secondary_reload_info sri; - - sri.icode = CODE_FOR_nothing; - sri.prev_sri = NULL; - class = targetm.secondary_reload (in_p, x, class, mode, &sri); - icode = sri.icode; - - /* If there are no secondary reloads at all, we return NO_REGS. - If an intermediate register is needed, we return its class. */ - if (icode == CODE_FOR_nothing || class != NO_REGS) - return class; - - /* No intermediate register is needed, but we have a special reload - pattern, which we assume for now needs a scratch register. */ - return scratch_reload_class (icode); -} - -/* ICODE is the insn_code of a reload pattern. Check that it has exactly - three operands, verify that operand 2 is an output operand, and return - its register class. - ??? We'd like to be able to handle any pattern with at least 2 operands, - for zero or more scratch registers, but that needs more infrastructure. */ -enum reg_class -scratch_reload_class (enum insn_code icode) -{ - const char *scratch_constraint; - char scratch_letter; - enum reg_class class; - - gcc_assert (insn_data[(int) icode].n_operands == 3); - scratch_constraint = insn_data[(int) icode].operand[2].constraint; - gcc_assert (*scratch_constraint == '='); - scratch_constraint++; - if (*scratch_constraint == '&') - scratch_constraint++; - scratch_letter = *scratch_constraint; - if (scratch_letter == 'r') - return GENERAL_REGS; - class = REG_CLASS_FROM_CONSTRAINT ((unsigned char) scratch_letter, - scratch_constraint); - gcc_assert (class != NO_REGS); - return class; -} +#endif /* HAVE_SECONDARY_RELOADS */ #ifdef SECONDARY_MEMORY_NEEDED @@ -643,15 +659,12 @@ clear_secondary_mem (void) } #endif /* SECONDARY_MEMORY_NEEDED */ - -/* Find the largest class which has at least one register valid in - mode INNER, and which for every such register, that register number - plus N is also valid in OUTER (if in range) and is cheap to move - into REGNO. Such a class must exist. */ +/* Find the largest class for which every register number plus N is valid in + M1 (if in range) and is cheap to move into REGNO. + Abort if no such class exists. */ static enum reg_class -find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED, - enum machine_mode inner ATTRIBUTE_UNUSED, int n, +find_valid_class (enum machine_mode m1 ATTRIBUTE_UNUSED, int n, unsigned int dest_regno ATTRIBUTE_UNUSED) { int best_cost = -1; @@ -665,22 +678,15 @@ find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED, for (class = 1; class < N_REG_CLASSES; class++) { int bad = 0; - int good = 0; - for (regno = 0; regno < FIRST_PSEUDO_REGISTER - n && ! bad; regno++) - if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)) - { - if (HARD_REGNO_MODE_OK (regno, inner)) - { - good = 1; - if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno + n) - || ! HARD_REGNO_MODE_OK (regno + n, outer)) - bad = 1; - } - } + for (regno = 0; regno < FIRST_PSEUDO_REGISTER && ! bad; regno++) + if (TEST_HARD_REG_BIT (reg_class_contents[class], regno) + && TEST_HARD_REG_BIT (reg_class_contents[class], regno + n) + && ! HARD_REGNO_MODE_OK (regno + n, m1)) + bad = 1; - if (bad || !good) + if (bad) continue; - cost = REGISTER_MOVE_COST (outer, class, dest_class); + cost = REGISTER_MOVE_COST (m1, class, dest_class); if ((reg_class_size[class] > best_size && (best_cost < 0 || best_cost >= cost)) @@ -688,11 +694,12 @@ find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED, { best_class = class; best_size = reg_class_size[class]; - best_cost = REGISTER_MOVE_COST (outer, class, dest_class); + best_cost = REGISTER_MOVE_COST (m1, class, dest_class); } } - gcc_assert (best_size != 0); + if (best_size == 0) + abort (); return best_class; } @@ -738,7 +745,7 @@ find_reusable_reload (rtx *p_in, rtx out, enum reg_class class, || (out != 0 && MATCHES (rld[i].out, out) && (in == 0 || rld[i].in == 0 || MATCHES (rld[i].in, in)))) && (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out)) - && (SMALL_REGISTER_CLASS_P (class) || SMALL_REGISTER_CLASSES) + && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES) && MERGABLE_RELOADS (type, rld[i].when_needed, opnum, rld[i].opnum)) return i; @@ -756,20 +763,20 @@ find_reusable_reload (rtx *p_in, rtx out, enum reg_class class, || TEST_HARD_REG_BIT (reg_class_contents[(int) class], true_regnum (rld[i].reg_rtx))) && out == 0 && rld[i].out == 0 && rld[i].in != 0 - && ((REG_P (in) - && GET_RTX_CLASS (GET_CODE (rld[i].in)) == RTX_AUTOINC + && ((GET_CODE (in) == REG + && GET_RTX_CLASS (GET_CODE (rld[i].in)) == 'a' && MATCHES (XEXP (rld[i].in, 0), in)) - || (REG_P (rld[i].in) - && GET_RTX_CLASS (GET_CODE (in)) == RTX_AUTOINC + || (GET_CODE (rld[i].in) == REG + && GET_RTX_CLASS (GET_CODE (in)) == 'a' && MATCHES (XEXP (in, 0), rld[i].in))) && (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out)) - && (SMALL_REGISTER_CLASS_P (class) || SMALL_REGISTER_CLASSES) + && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES) && MERGABLE_RELOADS (type, rld[i].when_needed, opnum, rld[i].opnum)) { /* Make sure reload_in ultimately has the increment, not the plain register. */ - if (REG_P (in)) + if (GET_CODE (in) == REG) *p_in = rld[i].in; return i; } @@ -796,7 +803,7 @@ reload_inner_reg_of_subreg (rtx x, enum machine_mode mode, int output) /* If INNER is not a hard register, then INNER will not need to be reloaded. */ - if (!REG_P (inner) + if (GET_CODE (inner) != REG || REGNO (inner) >= FIRST_PSEUDO_REGISTER) return 0; @@ -811,7 +818,7 @@ reload_inner_reg_of_subreg (rtx x, enum machine_mode mode, int output) && output && GET_MODE_SIZE (GET_MODE (inner)) > UNITS_PER_WORD && ((GET_MODE_SIZE (GET_MODE (inner)) / UNITS_PER_WORD) - != (int) hard_regno_nregs[REGNO (inner)][GET_MODE (inner)])); + != (int) HARD_REGNO_NREGS (REGNO (inner), GET_MODE (inner)))); } /* Return nonzero if IN can be reloaded into REGNO with mode MODE without @@ -840,14 +847,14 @@ can_reload_into (rtx in, int regno, enum machine_mode mode) technically this is a non-optional input-output reload, but IN is already a valid register, and has been chosen as the reload register. Speed this up, since it trivially works. */ - if (REG_P (in)) + if (GET_CODE (in) == REG) return 1; /* To test MEMs properly, we'd have to take into account all the reloads that are already scheduled, which can become quite complicated. And since we've already handled address reloads for this MEM, it should always succeed anyway. */ - if (MEM_P (in)) + if (GET_CODE (in) == MEM) return 1; /* If we can make a simple SET insn that does the job, everything should @@ -923,7 +930,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, it is not in a hard register, reload straight from the constant, since we want to get rid of such pseudo registers. Often this is done earlier, but not always in find_reloads_address. */ - if (in != 0 && REG_P (in)) + if (in != 0 && GET_CODE (in) == REG) { int regno = REGNO (in); @@ -935,7 +942,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, /* Likewise for OUT. Of course, OUT will never be equivalent to an actual constant, but it might be equivalent to a memory location (in the case of a parameter). */ - if (out != 0 && REG_P (out)) + if (out != 0 && GET_CODE (out) == REG) { int regno = REGNO (out); @@ -946,7 +953,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, /* If we have a read-write operand with an address side-effect, change either IN or OUT so the side-effect happens only once. */ - if (in != 0 && out != 0 && MEM_P (in) && rtx_equal_p (in, out)) + if (in != 0 && out != 0 && GET_CODE (in) == MEM && rtx_equal_p (in, out)) switch (GET_CODE (XEXP (in, 0))) { case POST_INC: case POST_DEC: case POST_MODIFY: @@ -999,9 +1006,9 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, && (CONSTANT_P (SUBREG_REG (in)) || GET_CODE (SUBREG_REG (in)) == PLUS || strict_low - || (((REG_P (SUBREG_REG (in)) + || (((GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER) - || MEM_P (SUBREG_REG (in))) + || GET_CODE (SUBREG_REG (in)) == MEM) && ((GET_MODE_SIZE (inmode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))) #ifdef LOAD_EXTEND_OP @@ -1011,7 +1018,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, && (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))) && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (in))) - && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != UNKNOWN) + && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != NIL) #endif #ifdef WORD_REGISTER_OPERATIONS || ((GET_MODE_SIZE (inmode) @@ -1021,7 +1028,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, / UNITS_PER_WORD))) #endif )) - || (REG_P (SUBREG_REG (in)) + || (GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER /* The case where out is nonzero is handled differently in the following statement. */ @@ -1031,15 +1038,18 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, > UNITS_PER_WORD) && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) / UNITS_PER_WORD) - != (int) hard_regno_nregs[REGNO (SUBREG_REG (in))] - [GET_MODE (SUBREG_REG (in))])) + != (int) HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)), + GET_MODE (SUBREG_REG (in))))) || ! HARD_REGNO_MODE_OK (subreg_regno (in), inmode))) - || (secondary_reload_class (1, class, inmode, in) != NO_REGS - && (secondary_reload_class (1, class, GET_MODE (SUBREG_REG (in)), - SUBREG_REG (in)) +#ifdef SECONDARY_INPUT_RELOAD_CLASS + || (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS + && (SECONDARY_INPUT_RELOAD_CLASS (class, + GET_MODE (SUBREG_REG (in)), + SUBREG_REG (in)) == NO_REGS)) +#endif #ifdef CANNOT_CHANGE_MODE_CLASS - || (REG_P (SUBREG_REG (in)) + || (GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER && REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), inmode)) @@ -1050,10 +1060,11 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, inloc = &SUBREG_REG (in); in = *inloc; #if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS) - if (MEM_P (in)) + if (GET_CODE (in) == MEM) /* This is supposed to happen only for paradoxical subregs made by combine.c. (SUBREG (MEM)) isn't supposed to occur other ways. */ - gcc_assert (GET_MODE_SIZE (GET_MODE (in)) <= GET_MODE_SIZE (inmode)); + if (GET_MODE_SIZE (GET_MODE (in)) > GET_MODE_SIZE (inmode)) + abort (); #endif inmode = GET_MODE (in); } @@ -1072,9 +1083,9 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, { enum reg_class in_class = class; - if (REG_P (SUBREG_REG (in))) + if (GET_CODE (SUBREG_REG (in)) == REG) in_class - = find_valid_class (inmode, GET_MODE (SUBREG_REG (in)), + = find_valid_class (inmode, subreg_regno_offset (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), SUBREG_BYTE (in), @@ -1104,9 +1115,9 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, #endif && (CONSTANT_P (SUBREG_REG (out)) || strict_low - || (((REG_P (SUBREG_REG (out)) + || (((GET_CODE (SUBREG_REG (out)) == REG && REGNO (SUBREG_REG (out)) >= FIRST_PSEUDO_REGISTER) - || MEM_P (SUBREG_REG (out))) + || GET_CODE (SUBREG_REG (out)) == MEM) && ((GET_MODE_SIZE (outmode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))) #ifdef WORD_REGISTER_OPERATIONS @@ -1117,22 +1128,25 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, / UNITS_PER_WORD))) #endif )) - || (REG_P (SUBREG_REG (out)) + || (GET_CODE (SUBREG_REG (out)) == REG && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER && ((GET_MODE_SIZE (outmode) <= UNITS_PER_WORD && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) > UNITS_PER_WORD) && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) / UNITS_PER_WORD) - != (int) hard_regno_nregs[REGNO (SUBREG_REG (out))] - [GET_MODE (SUBREG_REG (out))])) + != (int) HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)), + GET_MODE (SUBREG_REG (out))))) || ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode))) - || (secondary_reload_class (0, class, outmode, out) != NO_REGS - && (secondary_reload_class (0, class, GET_MODE (SUBREG_REG (out)), - SUBREG_REG (out)) +#ifdef SECONDARY_OUTPUT_RELOAD_CLASS + || (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS + && (SECONDARY_OUTPUT_RELOAD_CLASS (class, + GET_MODE (SUBREG_REG (out)), + SUBREG_REG (out)) == NO_REGS)) +#endif #ifdef CANNOT_CHANGE_MODE_CLASS - || (REG_P (SUBREG_REG (out)) + || (GET_CODE (SUBREG_REG (out)) == REG && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER && REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)), GET_MODE (SUBREG_REG (out)), @@ -1144,9 +1158,9 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, outloc = &SUBREG_REG (out); out = *outloc; #if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS) - gcc_assert (!MEM_P (out) - || GET_MODE_SIZE (GET_MODE (out)) - <= GET_MODE_SIZE (outmode)); + if (GET_CODE (out) == MEM + && GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode)) + abort (); #endif outmode = GET_MODE (out); } @@ -1168,7 +1182,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, dont_remove_subreg = 1; push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out), &SUBREG_REG (out), - find_valid_class (outmode, GET_MODE (SUBREG_REG (out)), + find_valid_class (outmode, subreg_regno_offset (REGNO (SUBREG_REG (out)), GET_MODE (SUBREG_REG (out)), SUBREG_BYTE (out), @@ -1179,46 +1193,37 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, } /* If IN appears in OUT, we can't share any input-only reload for IN. */ - if (in != 0 && out != 0 && MEM_P (out) - && (REG_P (in) || MEM_P (in)) + if (in != 0 && out != 0 && GET_CODE (out) == MEM + && (GET_CODE (in) == REG || GET_CODE (in) == MEM) && reg_overlap_mentioned_for_reload_p (in, XEXP (out, 0))) dont_share = 1; /* If IN is a SUBREG of a hard register, make a new REG. This simplifies some of the cases below. */ - if (in != 0 && GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in)) + if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER && ! dont_remove_subreg) in = gen_rtx_REG (GET_MODE (in), subreg_regno (in)); /* Similarly for OUT. */ if (out != 0 && GET_CODE (out) == SUBREG - && REG_P (SUBREG_REG (out)) + && GET_CODE (SUBREG_REG (out)) == REG && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER && ! dont_remove_subreg) out = gen_rtx_REG (GET_MODE (out), subreg_regno (out)); /* Narrow down the class of register wanted if that is desirable on this machine for efficiency. */ - { - enum reg_class preferred_class = class; - - if (in != 0) - preferred_class = PREFERRED_RELOAD_CLASS (in, class); + if (in != 0) + class = PREFERRED_RELOAD_CLASS (in, class); /* Output reloads may need analogous treatment, different in detail. */ #ifdef PREFERRED_OUTPUT_RELOAD_CLASS - if (out != 0) - preferred_class = PREFERRED_OUTPUT_RELOAD_CLASS (out, preferred_class); + if (out != 0) + class = PREFERRED_OUTPUT_RELOAD_CLASS (out, class); #endif - /* Discard what the target said if we cannot do it. */ - if (preferred_class != NO_REGS - || (optional && type == RELOAD_FOR_OUTPUT)) - class = preferred_class; - } - /* Make sure we use a class that can handle the actual pseudo inside any subreg. For example, on the 386, QImode regs can appear within SImode subregs. Although GENERAL_REGS @@ -1246,8 +1251,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, mode = outmode; if (mode == VOIDmode) { - error_for_asm (this_insn, "cannot reload integer constant " - "operand in %<asm%>"); + error_for_asm (this_insn, "cannot reload integer constant operand in `asm'"); mode = word_mode; if (in != 0) inmode = word_mode; @@ -1258,7 +1262,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, if (HARD_REGNO_MODE_OK (i, mode) && TEST_HARD_REG_BIT (reg_class_contents[(int) class], i)) { - int nregs = hard_regno_nregs[i][mode]; + int nregs = HARD_REGNO_NREGS (i, mode); int j; for (j = 1; j < nregs; j++) @@ -1269,29 +1273,17 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, } if (i == FIRST_PSEUDO_REGISTER) { - error_for_asm (this_insn, "impossible register constraint " - "in %<asm%>"); - /* Avoid further trouble with this insn. */ - PATTERN (this_insn) = gen_rtx_USE (VOIDmode, const0_rtx); - /* We used to continue here setting class to ALL_REGS, but it triggers - sanity check on i386 for: - void foo(long double d) - { - asm("" :: "a" (d)); - } - Returning zero here ought to be safe as we take care in - find_reloads to not process the reloads when instruction was - replaced by USE. */ - - return 0; + error_for_asm (this_insn, "impossible register constraint in `asm'"); + class = ALL_REGS; } } /* Optional output reloads are always OK even if we have no register class, since the function of these reloads is only to have spill_reg_store etc. set, so that the storing insn can be deleted later. */ - gcc_assert (class != NO_REGS - || (optional != 0 && type == RELOAD_FOR_OUTPUT)); + if (class == NO_REGS + && (optional == 0 || type != RELOAD_FOR_OUTPUT)) + abort (); i = find_reusable_reload (&in, out, class, type, opnum, dont_share); @@ -1301,23 +1293,26 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, and IN or CLASS and OUT. Get the icode and push any required reloads needed for each of them if so. */ +#ifdef SECONDARY_INPUT_RELOAD_CLASS if (in != 0) secondary_in_reload = push_secondary_reload (1, in, opnum, optional, class, inmode, type, - &secondary_in_icode, NULL); + &secondary_in_icode); +#endif + +#ifdef SECONDARY_OUTPUT_RELOAD_CLASS if (out != 0 && GET_CODE (out) != SCRATCH) secondary_out_reload = push_secondary_reload (0, out, opnum, optional, class, outmode, - type, &secondary_out_icode, NULL); + type, &secondary_out_icode); +#endif /* We found no existing reload suitable for re-use. So add an additional reload. */ #ifdef SECONDARY_MEMORY_NEEDED /* If a memory location is needed for the copy, make one. */ - if (in != 0 - && (REG_P (in) - || (GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in)))) + if (in != 0 && (GET_CODE (in) == REG || GET_CODE (in) == SUBREG) && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)), class, inmode)) @@ -1347,9 +1342,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, n_reloads++; #ifdef SECONDARY_MEMORY_NEEDED - if (out != 0 - && (REG_P (out) - || (GET_CODE (out) == SUBREG && REG_P (SUBREG_REG (out)))) + if (out != 0 && (GET_CODE (out) == REG || GET_CODE (out) == SUBREG) && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER && SECONDARY_MEMORY_NEEDED (class, REGNO_REG_CLASS (reg_or_subregno (out)), @@ -1444,7 +1437,8 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, /* If we did not find a nonzero amount-to-increment-by, that contradicts the belief that IN is being incremented in an address in this insn. */ - gcc_assert (rld[i].inc != 0); + if (rld[i].inc == 0) + abort (); } #endif @@ -1492,7 +1486,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, The easiest way to tell the caller that is to give a phony value for the incoming operand (same as outgoing one). */ if (rld[i].reg_rtx == out - && (REG_P (in) || CONSTANT_P (in)) + && (GET_CODE (in) == REG || CONSTANT_P (in)) && 0 != find_equiv_reg (in, this_insn, 0, REGNO (out), static_reload_reg_p, i, inmode)) rld[i].in = out; @@ -1510,7 +1504,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, But if there is no spilling in this block, that is OK. An explicitly used hard reg cannot be a spill reg. */ - if (rld[i].reg_rtx == 0 && in != 0 && hard_regs_live_known) + if (rld[i].reg_rtx == 0 && in != 0) { rtx note; int regno; @@ -1521,18 +1515,13 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1)) if (REG_NOTE_KIND (note) == REG_DEAD - && REG_P (XEXP (note, 0)) + && GET_CODE (XEXP (note, 0)) == REG && (regno = REGNO (XEXP (note, 0))) < FIRST_PSEUDO_REGISTER && reg_mentioned_p (XEXP (note, 0), in) - /* Check that we don't use a hardreg for an uninitialized - pseudo. See also find_dummy_reload(). */ - && (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER - || ! bitmap_bit_p (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end, - ORIGINAL_REGNO (XEXP (note, 0)))) && ! refers_to_regno_for_reload_p (regno, (regno - + hard_regno_nregs[regno] - [rel_mode]), + + HARD_REGNO_NREGS (regno, + rel_mode)), PATTERN (this_insn), inloc) /* If this is also an output reload, IN cannot be used as the reload register if it is set in this insn unless IN @@ -1540,8 +1529,8 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, && (out == 0 || in == out || ! hard_reg_set_here_p (regno, (regno - + hard_regno_nregs[regno] - [rel_mode]), + + HARD_REGNO_NREGS (regno, + rel_mode)), PATTERN (this_insn))) /* ??? Why is this code so different from the previous? Is there any simple coherent way to describe the two together? @@ -1559,8 +1548,8 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, && HARD_REGNO_MODE_OK (regno, outmode)) { unsigned int offs; - unsigned int nregs = MAX (hard_regno_nregs[regno][inmode], - hard_regno_nregs[regno][outmode]); + unsigned int nregs = MAX (HARD_REGNO_NREGS (regno, inmode), + HARD_REGNO_NREGS (regno, outmode)); for (offs = 0; offs < nregs; offs++) if (fixed_regs[regno + offs] @@ -1570,7 +1559,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, if (offs == nregs && (! (refers_to_regno_for_reload_p - (regno, (regno + hard_regno_nregs[regno][inmode]), + (regno, (regno + HARD_REGNO_NREGS (regno, inmode)), in, (rtx *)0)) || can_reload_into (in, regno, inmode))) { @@ -1765,7 +1754,7 @@ combine_reloads (void) If the same reload reg is used for both reg 69 and the result to be stored in memory, then that result will clobber the address of the memory ref. */ - && ! (REG_P (rld[i].in) + && ! (GET_CODE (rld[i].in) == REG && reg_overlap_mentioned_for_reload_p (rld[i].in, rld[output_reload].out)))) && ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode, @@ -1834,15 +1823,15 @@ combine_reloads (void) up can fully hold our output reload. */ for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1)) if (REG_NOTE_KIND (note) == REG_DEAD - && REG_P (XEXP (note, 0)) + && GET_CODE (XEXP (note, 0)) == REG && ! reg_overlap_mentioned_for_reload_p (XEXP (note, 0), rld[output_reload].out) && REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER && HARD_REGNO_MODE_OK (REGNO (XEXP (note, 0)), rld[output_reload].outmode) && TEST_HARD_REG_BIT (reg_class_contents[(int) rld[output_reload].class], REGNO (XEXP (note, 0))) - && (hard_regno_nregs[REGNO (XEXP (note, 0))][rld[output_reload].outmode] - <= hard_regno_nregs[REGNO (XEXP (note, 0))][GET_MODE (XEXP (note, 0))]) + && (HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), rld[output_reload].outmode) + <= HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), GET_MODE (XEXP (note, 0)))) /* Ensure that a secondary or tertiary reload for this output won't want this register. */ && ((secondary_out = rld[output_reload].secondary_out_reload) == -1 @@ -1853,12 +1842,7 @@ combine_reloads (void) || ! (TEST_HARD_REG_BIT (reg_class_contents[(int) rld[secondary_out].class], REGNO (XEXP (note, 0))))))) - && ! fixed_regs[REGNO (XEXP (note, 0))] - /* Check that we don't use a hardreg for an uninitialized - pseudo. See also find_dummy_reload(). */ - && (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER - || ! bitmap_bit_p (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end, - ORIGINAL_REGNO (XEXP (note, 0))))) + && ! fixed_regs[REGNO (XEXP (note, 0))]) { rld[output_reload].reg_rtx = gen_rtx_REG (rld[output_reload].outmode, @@ -1911,7 +1895,7 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc, /* Find the inside of any subregs. */ while (GET_CODE (out) == SUBREG) { - if (REG_P (SUBREG_REG (out)) + if (GET_CODE (SUBREG_REG (out)) == REG && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER) out_offset += subreg_regno_offset (REGNO (SUBREG_REG (out)), GET_MODE (SUBREG_REG (out)), @@ -1921,7 +1905,7 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc, } while (GET_CODE (in) == SUBREG) { - if (REG_P (SUBREG_REG (in)) + if (GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER) in_offset += subreg_regno_offset (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), @@ -1932,18 +1916,14 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc, /* Narrow down the reg class, the same way push_reload will; otherwise we might find a dummy now, but push_reload won't. */ - { - enum reg_class preferred_class = PREFERRED_RELOAD_CLASS (in, class); - if (preferred_class != NO_REGS) - class = preferred_class; - } + class = PREFERRED_RELOAD_CLASS (in, class); /* See if OUT will do. */ - if (REG_P (out) + if (GET_CODE (out) == REG && REGNO (out) < FIRST_PSEUDO_REGISTER) { unsigned int regno = REGNO (out) + out_offset; - unsigned int nwords = hard_regno_nregs[regno][outmode]; + unsigned int nwords = HARD_REGNO_NREGS (regno, outmode); rtx saved_rtx; /* When we consider whether the insn uses OUT, @@ -1972,7 +1952,7 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc, if (i == nwords) { - if (REG_P (real_out)) + if (GET_CODE (real_out) == REG) value = real_out; else value = gen_rtx_REG (outmode, regno); @@ -1989,7 +1969,7 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc, Also, the result can't go in IN if IN is used within OUT, or if OUT is an earlyclobber and IN appears elsewhere in the insn. */ if (hard_regs_live_known - && REG_P (in) + && GET_CODE (in) == REG && REGNO (in) < FIRST_PSEUDO_REGISTER && (value == 0 || find_reg_note (this_insn, REG_UNUSED, real_out)) @@ -2001,20 +1981,10 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc, is a subreg, and in that case, out has a real mode. */ (GET_MODE (out) != VOIDmode - ? GET_MODE (out) : outmode)) - /* But only do all this if we can be sure, that this input - operand doesn't correspond with an uninitialized pseudoreg. - global can assign some hardreg to it, which is the same as - a different pseudo also currently live (as it can ignore the - conflict). So we never must introduce writes to such hardregs, - as they would clobber the other live pseudo using the same. - See also PR20973. */ - && (ORIGINAL_REGNO (in) < FIRST_PSEUDO_REGISTER - || ! bitmap_bit_p (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end, - ORIGINAL_REGNO (in)))) + ? GET_MODE (out) : outmode))) { unsigned int regno = REGNO (in) + in_offset; - unsigned int nwords = hard_regno_nregs[regno][inmode]; + unsigned int nwords = HARD_REGNO_NREGS (regno, inmode); if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, (rtx*) 0) && ! hard_reg_set_here_p (regno, regno + nwords, @@ -2037,7 +2007,7 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc, dies here. So don't bother copying value to it. */ if (for_real >= 0 && value == real_out) rld[for_real].out = 0; - if (REG_P (real_in)) + if (GET_CODE (real_in) == REG) value = real_in; else value = gen_rtx_REG (inmode, regno); @@ -2080,13 +2050,13 @@ hard_reg_set_here_p (unsigned int beg_regno, unsigned int end_regno, rtx x) while (GET_CODE (op0) == SUBREG) op0 = SUBREG_REG (op0); - if (REG_P (op0)) + if (GET_CODE (op0) == REG) { unsigned int r = REGNO (op0); /* See if this reg overlaps range under consideration. */ if (r < end_regno - && r + hard_regno_nregs[r][GET_MODE (op0)] > beg_regno) + && r + HARD_REGNO_NREGS (r, GET_MODE (op0)) > beg_regno) return 1; } } @@ -2141,9 +2111,9 @@ operands_match_p (rtx x, rtx y) if (x == y) return 1; - if ((code == REG || (code == SUBREG && REG_P (SUBREG_REG (x)))) - && (REG_P (y) || (GET_CODE (y) == SUBREG - && REG_P (SUBREG_REG (y))))) + if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG)) + && (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG + && GET_CODE (SUBREG_REG (y)) == REG))) { int j; @@ -2180,11 +2150,11 @@ operands_match_p (rtx x, rtx y) if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD && SCALAR_INT_MODE_P (GET_MODE (x)) && i < FIRST_PSEUDO_REGISTER) - i += hard_regno_nregs[i][GET_MODE (x)] - 1; + i += HARD_REGNO_NREGS (i, GET_MODE (x)) - 1; if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (y)) > UNITS_PER_WORD && SCALAR_INT_MODE_P (GET_MODE (y)) && j < FIRST_PSEUDO_REGISTER) - j += hard_regno_nregs[j][GET_MODE (y)] - 1; + j += HARD_REGNO_NREGS (j, GET_MODE (y)) - 1; return i == j; } @@ -2207,30 +2177,20 @@ operands_match_p (rtx x, rtx y) slow: - /* Now we have disposed of all the cases in which different rtx codes - can match. */ + /* Now we have disposed of all the cases + in which different rtx codes can match. */ if (code != GET_CODE (y)) return 0; + if (code == LABEL_REF) + return XEXP (x, 0) == XEXP (y, 0); + if (code == SYMBOL_REF) + return XSTR (x, 0) == XSTR (y, 0); /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */ + if (GET_MODE (x) != GET_MODE (y)) return 0; - switch (code) - { - case CONST_INT: - case CONST_DOUBLE: - return 0; - - case LABEL_REF: - return XEXP (x, 0) == XEXP (y, 0); - case SYMBOL_REF: - return XSTR (x, 0) == XSTR (y, 0); - - default: - break; - } - /* Compare the elements. If any pair of corresponding elements fail to match, return 0 for the whole things. */ @@ -2281,7 +2241,7 @@ operands_match_p (rtx x, rtx y) contain anything but integers and other rtx's, except for within LABEL_REFs and SYMBOL_REFs. */ default: - gcc_unreachable (); + abort (); } } return 1 + success_2; @@ -2301,104 +2261,104 @@ decompose (rtx x) struct decomposition val; int all_const = 0; - memset (&val, 0, sizeof (val)); + val.reg_flag = 0; + val.safe = 0; + val.base = 0; + if (GET_CODE (x) == MEM) + { + rtx base = NULL_RTX, offset = 0; + rtx addr = XEXP (x, 0); + + if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC + || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC) + { + val.base = XEXP (addr, 0); + val.start = -GET_MODE_SIZE (GET_MODE (x)); + val.end = GET_MODE_SIZE (GET_MODE (x)); + val.safe = REGNO (val.base) == STACK_POINTER_REGNUM; + return val; + } + + if (GET_CODE (addr) == PRE_MODIFY || GET_CODE (addr) == POST_MODIFY) + { + if (GET_CODE (XEXP (addr, 1)) == PLUS + && XEXP (addr, 0) == XEXP (XEXP (addr, 1), 0) + && CONSTANT_P (XEXP (XEXP (addr, 1), 1))) + { + val.base = XEXP (addr, 0); + val.start = -INTVAL (XEXP (XEXP (addr, 1), 1)); + val.end = INTVAL (XEXP (XEXP (addr, 1), 1)); + val.safe = REGNO (val.base) == STACK_POINTER_REGNUM; + return val; + } + } + + if (GET_CODE (addr) == CONST) + { + addr = XEXP (addr, 0); + all_const = 1; + } + if (GET_CODE (addr) == PLUS) + { + if (CONSTANT_P (XEXP (addr, 0))) + { + base = XEXP (addr, 1); + offset = XEXP (addr, 0); + } + else if (CONSTANT_P (XEXP (addr, 1))) + { + base = XEXP (addr, 0); + offset = XEXP (addr, 1); + } + } - switch (GET_CODE (x)) + if (offset == 0) + { + base = addr; + offset = const0_rtx; + } + if (GET_CODE (offset) == CONST) + offset = XEXP (offset, 0); + if (GET_CODE (offset) == PLUS) + { + if (GET_CODE (XEXP (offset, 0)) == CONST_INT) + { + base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 1)); + offset = XEXP (offset, 0); + } + else if (GET_CODE (XEXP (offset, 1)) == CONST_INT) + { + base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 0)); + offset = XEXP (offset, 1); + } + else + { + base = gen_rtx_PLUS (GET_MODE (base), base, offset); + offset = const0_rtx; + } + } + else if (GET_CODE (offset) != CONST_INT) + { + base = gen_rtx_PLUS (GET_MODE (base), base, offset); + offset = const0_rtx; + } + + if (all_const && GET_CODE (base) == PLUS) + base = gen_rtx_CONST (GET_MODE (base), base); + + if (GET_CODE (offset) != CONST_INT) + abort (); + + val.start = INTVAL (offset); + val.end = val.start + GET_MODE_SIZE (GET_MODE (x)); + val.base = base; + return val; + } + else if (GET_CODE (x) == REG) { - case MEM: - { - rtx base = NULL_RTX, offset = 0; - rtx addr = XEXP (x, 0); - - if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC - || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC) - { - val.base = XEXP (addr, 0); - val.start = -GET_MODE_SIZE (GET_MODE (x)); - val.end = GET_MODE_SIZE (GET_MODE (x)); - val.safe = REGNO (val.base) == STACK_POINTER_REGNUM; - return val; - } - - if (GET_CODE (addr) == PRE_MODIFY || GET_CODE (addr) == POST_MODIFY) - { - if (GET_CODE (XEXP (addr, 1)) == PLUS - && XEXP (addr, 0) == XEXP (XEXP (addr, 1), 0) - && CONSTANT_P (XEXP (XEXP (addr, 1), 1))) - { - val.base = XEXP (addr, 0); - val.start = -INTVAL (XEXP (XEXP (addr, 1), 1)); - val.end = INTVAL (XEXP (XEXP (addr, 1), 1)); - val.safe = REGNO (val.base) == STACK_POINTER_REGNUM; - return val; - } - } - - if (GET_CODE (addr) == CONST) - { - addr = XEXP (addr, 0); - all_const = 1; - } - if (GET_CODE (addr) == PLUS) - { - if (CONSTANT_P (XEXP (addr, 0))) - { - base = XEXP (addr, 1); - offset = XEXP (addr, 0); - } - else if (CONSTANT_P (XEXP (addr, 1))) - { - base = XEXP (addr, 0); - offset = XEXP (addr, 1); - } - } - - if (offset == 0) - { - base = addr; - offset = const0_rtx; - } - if (GET_CODE (offset) == CONST) - offset = XEXP (offset, 0); - if (GET_CODE (offset) == PLUS) - { - if (GET_CODE (XEXP (offset, 0)) == CONST_INT) - { - base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 1)); - offset = XEXP (offset, 0); - } - else if (GET_CODE (XEXP (offset, 1)) == CONST_INT) - { - base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 0)); - offset = XEXP (offset, 1); - } - else - { - base = gen_rtx_PLUS (GET_MODE (base), base, offset); - offset = const0_rtx; - } - } - else if (GET_CODE (offset) != CONST_INT) - { - base = gen_rtx_PLUS (GET_MODE (base), base, offset); - offset = const0_rtx; - } - - if (all_const && GET_CODE (base) == PLUS) - base = gen_rtx_CONST (GET_MODE (base), base); - - gcc_assert (GET_CODE (offset) == CONST_INT); - - val.start = INTVAL (offset); - val.end = val.start + GET_MODE_SIZE (GET_MODE (x)); - val.base = base; - } - break; - - case REG: val.reg_flag = 1; val.start = true_regnum (x); - if (val.start < 0 || val.start >= FIRST_PSEUDO_REGISTER) + if (val.start < 0) { /* A pseudo with no hard reg. */ val.start = REGNO (x); @@ -2406,32 +2366,27 @@ decompose (rtx x) } else /* A hard reg. */ - val.end = val.start + hard_regno_nregs[val.start][GET_MODE (x)]; - break; - - case SUBREG: - if (!REG_P (SUBREG_REG (x))) + val.end = val.start + HARD_REGNO_NREGS (val.start, GET_MODE (x)); + } + else if (GET_CODE (x) == SUBREG) + { + if (GET_CODE (SUBREG_REG (x)) != REG) /* This could be more precise, but it's good enough. */ return decompose (SUBREG_REG (x)); val.reg_flag = 1; val.start = true_regnum (x); - if (val.start < 0 || val.start >= FIRST_PSEUDO_REGISTER) + if (val.start < 0) return decompose (SUBREG_REG (x)); else /* A hard reg. */ - val.end = val.start + hard_regno_nregs[val.start][GET_MODE (x)]; - break; - - case SCRATCH: - /* This hasn't been assigned yet, so it can't conflict yet. */ - val.safe = 1; - break; - - default: - gcc_assert (CONSTANT_P (x)); - val.safe = 1; - break; + val.end = val.start + HARD_REGNO_NREGS (val.start, GET_MODE (x)); } + else if (CONSTANT_P (x) + /* This hasn't been assigned yet, so it can't conflict yet. */ + || GET_CODE (x) == SCRATCH) + val.safe = 1; + else + abort (); return val; } @@ -2448,9 +2403,10 @@ immune_p (rtx x, rtx y, struct decomposition ydata) if (ydata.safe) return 1; - gcc_assert (MEM_P (y)); + if (GET_CODE (y) != MEM) + abort (); /* If Y is memory and X is not, Y can't affect X. */ - if (!MEM_P (x)) + if (GET_CODE (x) != MEM) return 1; xdata = decompose (x); @@ -2525,11 +2481,9 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, a register. */ enum reg_class preferred_class[MAX_RECOG_OPERANDS]; char pref_or_nothing[MAX_RECOG_OPERANDS]; - /* Nonzero for a MEM operand whose entire address needs a reload. - May be -1 to indicate the entire address may or may not need a reload. */ + /* Nonzero for a MEM operand whose entire address needs a reload. */ int address_reloaded[MAX_RECOG_OPERANDS]; - /* Nonzero for an address operand that needs to be completely reloaded. - May be -1 to indicate the entire operand may or may not need a reload. */ + /* Nonzero for an address operand that needs to be completely reloaded. */ int address_operand_reloaded[MAX_RECOG_OPERANDS]; /* Value of enum reload_type to use for operand. */ enum reload_type operand_type[MAX_RECOG_OPERANDS]; @@ -2578,7 +2532,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, /* JUMP_INSNs and CALL_INSNs are not allowed to have any output reloads; neither are insns that SET cc0. Insns that use CC0 are not allowed to have any input reloads. */ - if (JUMP_P (insn) || CALL_P (insn)) + if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CALL_INSN) no_output_reloads = 1; #ifdef HAVE_cc0 @@ -2604,9 +2558,9 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, is cheap to move between them. If it is not, there may not be an insn to do the copy, so we may need a reload. */ if (GET_CODE (body) == SET - && REG_P (SET_DEST (body)) + && GET_CODE (SET_DEST (body)) == REG && REGNO (SET_DEST (body)) < FIRST_PSEUDO_REGISTER - && REG_P (SET_SRC (body)) + && GET_CODE (SET_SRC (body)) == REG && REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER && REGISTER_MOVE_COST (GET_MODE (SET_SRC (body)), REGNO_REG_CLASS (REGNO (SET_SRC (body))), @@ -2652,69 +2606,62 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, while ((c = *p)) { p += CONSTRAINT_LEN (c, p); - switch (c) + if (c == '=') + modified[i] = RELOAD_WRITE; + else if (c == '+') + modified[i] = RELOAD_READ_WRITE; + else if (c == '%') { - case '=': - modified[i] = RELOAD_WRITE; - break; - case '+': - modified[i] = RELOAD_READ_WRITE; - break; - case '%': - { - /* The last operand should not be marked commutative. */ - gcc_assert (i != noperands - 1); - - /* We currently only support one commutative pair of - operands. Some existing asm code currently uses more - than one pair. Previously, that would usually work, - but sometimes it would crash the compiler. We - continue supporting that case as well as we can by - silently ignoring all but the first pair. In the - future we may handle it correctly. */ - if (commutative < 0) - commutative = i; - else - gcc_assert (this_insn_is_asm); - } - break; - /* Use of ISDIGIT is tempting here, but it may get expensive because - of locale support we don't want. */ - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - c = strtoul (p - 1, &p, 10); + /* The last operand should not be marked commutative. */ + if (i == noperands - 1) + abort (); + + /* We currently only support one commutative pair of + operands. Some existing asm code currently uses more + than one pair. Previously, that would usually work, + but sometimes it would crash the compiler. We + continue supporting that case as well as we can by + silently ignoring all but the first pair. In the + future we may handle it correctly. */ + if (commutative < 0) + commutative = i; + else if (!this_insn_is_asm) + abort (); + } + else if (ISDIGIT (c)) + { + c = strtoul (p - 1, &p, 10); - operands_match[c][i] - = operands_match_p (recog_data.operand[c], - recog_data.operand[i]); + operands_match[c][i] + = operands_match_p (recog_data.operand[c], + recog_data.operand[i]); - /* An operand may not match itself. */ - gcc_assert (c != i); + /* An operand may not match itself. */ + if (c == i) + abort (); - /* If C can be commuted with C+1, and C might need to match I, - then C+1 might also need to match I. */ - if (commutative >= 0) - { - if (c == commutative || c == commutative + 1) - { - int other = c + (c == commutative ? 1 : -1); - operands_match[other][i] - = operands_match_p (recog_data.operand[other], - recog_data.operand[i]); - } - if (i == commutative || i == commutative + 1) - { - int other = i + (i == commutative ? 1 : -1); - operands_match[c][other] - = operands_match_p (recog_data.operand[c], - recog_data.operand[other]); - } - /* Note that C is supposed to be less than I. - No need to consider altering both C and I because in - that case we would alter one into the other. */ - } - } + /* If C can be commuted with C+1, and C might need to match I, + then C+1 might also need to match I. */ + if (commutative >= 0) + { + if (c == commutative || c == commutative + 1) + { + int other = c + (c == commutative ? 1 : -1); + operands_match[other][i] + = operands_match_p (recog_data.operand[other], + recog_data.operand[i]); + } + if (i == commutative || i == commutative + 1) + { + int other = i + (i == commutative ? 1 : -1); + operands_match[c][other] + = operands_match_p (recog_data.operand[c], + recog_data.operand[other]); + } + /* Note that C is supposed to be less than I. + No need to consider altering both C and I because in + that case we would alter one into the other. */ + } } } } @@ -2755,7 +2702,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, /* If we now have a simple operand where we used to have a PLUS or MULT, re-recognize and try again. */ - if ((OBJECT_P (*recog_data.operand_loc[i]) + if ((GET_RTX_CLASS (GET_CODE (*recog_data.operand_loc[i])) == 'o' || GET_CODE (*recog_data.operand_loc[i]) == SUBREG) && (GET_CODE (recog_data.operand[i]) == MULT || GET_CODE (recog_data.operand[i]) == PLUS)) @@ -2801,8 +2748,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, wider reload. */ if (replace - && MEM_P (op) - && REG_P (reg) + && GET_CODE (op) == MEM + && GET_CODE (reg) == REG && (GET_MODE_SIZE (GET_MODE (reg)) >= GET_MODE_SIZE (GET_MODE (op)))) set_unique_reg_note (emit_insn_before (gen_rtx_USE (VOIDmode, reg), @@ -2811,7 +2758,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, substed_operand[i] = recog_data.operand[i] = op; } - else if (code == PLUS || GET_RTX_CLASS (code) == RTX_UNARY) + else if (code == PLUS || GET_RTX_CLASS (code) == '1') /* We can get a PLUS as an "operand" as a result of register elimination. See eliminate_regs and gen_reload. We handle a unary operator by reloading the operand. */ @@ -2939,7 +2886,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, /* If the predicate accepts a unary operator, it means that we need to reload the operand, but do not do this for match_operator and friends. */ - if (UNARY_P (operand) && *p != 0) + if (GET_RTX_CLASS (GET_CODE (operand)) == '1' && *p != 0) operand = XEXP (operand, 0); /* If the operand is a SUBREG, extract @@ -2952,7 +2899,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, it is a hard reg. This is because it is passed to reg_fits_class_p if it is a REG and all pseudos return 0 from that function. */ - if (REG_P (SUBREG_REG (operand)) + if (GET_CODE (SUBREG_REG (operand)) == REG && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER) { if (!subreg_offset_representable_p @@ -2995,8 +2942,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, ??? When is it right at this stage to have a subreg of a mem that is _not_ to be handled specially? IMO those should have been reduced to just a mem. */ - || ((MEM_P (operand) - || (REG_P (operand) + || ((GET_CODE (operand) == MEM + || (GET_CODE (operand)== REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER)) #ifndef WORD_REGISTER_OPERATIONS && (((GET_MODE_BITSIZE (GET_MODE (operand)) @@ -3011,7 +2958,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, && (GET_MODE_SIZE (operand_mode[i]) > GET_MODE_SIZE (GET_MODE (operand))) && INTEGRAL_MODE_P (GET_MODE (operand)) - && LOAD_EXTEND_OP (GET_MODE (operand)) != UNKNOWN) + && LOAD_EXTEND_OP (GET_MODE (operand)) != NIL) #endif ) #endif @@ -3106,7 +3053,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, offsettable address was expected, then we must reject this combination, because we can't reload it. */ if (this_alternative_offmemok[m] - && MEM_P (recog_data.operand[m]) + && GET_CODE (recog_data.operand[m]) == MEM && this_alternative[m] == (int) NO_REGS && ! this_alternative_win[m]) bad = 1; @@ -3172,8 +3119,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, case 'p': /* All necessary reloads for an address_operand were handled in find_reloads_address. */ - this_alternative[i] - = (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH); + this_alternative[i] = (int) MODE_BASE_REG_CLASS (VOIDmode); win = 1; badop = 0; break; @@ -3181,18 +3127,20 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, case 'm': if (force_reload) break; - if (MEM_P (operand) - || (REG_P (operand) + if (GET_CODE (operand) == MEM + || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (operand)] < 0)) win = 1; - if (CONST_POOL_OK_P (operand)) + if (CONSTANT_P (operand) + /* force_const_mem does not accept HIGH. */ + && GET_CODE (operand) != HIGH) badop = 0; constmemok = 1; break; case '<': - if (MEM_P (operand) + if (GET_CODE (operand) == MEM && ! address_reloaded[i] && (GET_CODE (XEXP (operand, 0)) == PRE_DEC || GET_CODE (XEXP (operand, 0)) == POST_DEC)) @@ -3200,7 +3148,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, break; case '>': - if (MEM_P (operand) + if (GET_CODE (operand) == MEM && ! address_reloaded[i] && (GET_CODE (XEXP (operand, 0)) == PRE_INC || GET_CODE (XEXP (operand, 0)) == POST_INC)) @@ -3211,14 +3159,14 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, case 'V': if (force_reload) break; - if (MEM_P (operand) + if (GET_CODE (operand) == MEM && ! (ind_levels ? offsettable_memref_p (operand) : offsettable_nonstrict_memref_p (operand)) /* Certain mem addresses will become offsettable after they themselves are reloaded. This is important; we don't want our own handling of unoffsettables to override the handling of reg_equiv_address. */ - && !(REG_P (XEXP (operand, 0)) + && !(GET_CODE (XEXP (operand, 0)) == REG && (ind_levels == 0 || reg_equiv_address[REGNO (XEXP (operand, 0))] != 0))) win = 1; @@ -3228,7 +3176,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, case 'o': if (force_reload) break; - if ((MEM_P (operand) + if ((GET_CODE (operand) == MEM /* If IND_LEVELS, find_reloads_address won't reload a pseudo that didn't get a hard reg, so we have to reject that case. */ @@ -3236,8 +3184,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, : offsettable_nonstrict_memref_p (operand)) /* A reloaded address is offsettable because it is now just a simple register indirect. */ - || address_reloaded[i] == 1)) - || (REG_P (operand) + || address_reloaded[i])) + || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (operand)] < 0 /* If reg_equiv_address is nonzero, we will be @@ -3248,8 +3196,9 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, && offsettable_memref_p (reg_equiv_mem[REGNO (operand)])) || (reg_equiv_address[REGNO (operand)] != 0)))) win = 1; - if (CONST_POOL_OK_P (operand) - || MEM_P (operand)) + /* force_const_mem does not accept HIGH. */ + if ((CONSTANT_P (operand) && GET_CODE (operand) != HIGH) + || GET_CODE (operand) == MEM) badop = 0; constmemok = 1; offmemok = 1; @@ -3284,7 +3233,10 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, break; case 'i': if (CONSTANT_P (operand) - && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand))) +#ifdef LEGITIMATE_PIC_OPERAND_P + && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand)) +#endif + ) win = 1; break; @@ -3309,7 +3261,6 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, break; case 'X': - force_reload = 0; win = 1; break; @@ -3320,11 +3271,13 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, && GET_CODE (operand) != PLUS /* A SCRATCH is not a valid operand. */ && GET_CODE (operand) != SCRATCH +#ifdef LEGITIMATE_PIC_OPERAND_P && (! CONSTANT_P (operand) || ! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand)) +#endif && (GENERAL_REGS == ALL_REGS - || !REG_P (operand) + || GET_CODE (operand) != REG || (REGNO (operand) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (operand)] < 0))) win = 1; @@ -3347,13 +3300,13 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, win = 1; /* If the address was already reloaded, we win as well. */ - else if (MEM_P (operand) - && address_reloaded[i] == 1) + else if (GET_CODE (operand) == MEM + && address_reloaded[i]) win = 1; /* Likewise if the address will be reloaded because reg_equiv_address is nonzero. For reg_equiv_mem we have to check. */ - else if (REG_P (operand) + else if (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (operand)] < 0 && ((reg_equiv_mem[REGNO (operand)] != 0 @@ -3364,8 +3317,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, /* If we didn't already win, we can reload constants via force_const_mem, and other MEMs by reloading the address like for 'o'. */ - if (CONST_POOL_OK_P (operand) - || MEM_P (operand)) + if ((CONSTANT_P (operand) && GET_CODE (operand) != HIGH) + || GET_CODE (operand) == MEM) badop = 0; constmemok = 1; offmemok = 1; @@ -3378,8 +3331,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, /* If we didn't already win, we can reload the address into a base register. */ - this_alternative[i] - = (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH); + this_alternative[i] = (int) MODE_BASE_REG_CLASS (VOIDmode); badop = 0; break; } @@ -3398,7 +3350,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, if (GET_MODE (operand) == BLKmode) break; winreg = 1; - if (REG_P (operand) + if (GET_CODE (operand) == REG && reg_fits_class_p (operand, this_alternative[i], offset, GET_MODE (recog_data.operand[i]))) win = 1; @@ -3428,7 +3380,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, if (badop) bad = 1; /* Alternative loses if it has no regs for a reg operand. */ - if (REG_P (operand) + if (GET_CODE (operand) == REG && this_alternative[i] == (int) NO_REGS && this_alternative_matches[i] < 0) bad = 1; @@ -3441,7 +3393,9 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, an early reload pass. Note that the test here is precisely the same as in the code below that calls force_const_mem. */ - if (CONST_POOL_OK_P (operand) + if (CONSTANT_P (operand) + /* force_const_mem does not accept HIGH. */ + && GET_CODE (operand) != HIGH && ((PREFERRED_RELOAD_CLASS (operand, (enum reg_class) this_alternative[i]) == NO_REGS) @@ -3453,10 +3407,22 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, losers++; } + /* If we can't reload this value at all, reject this + alternative. Note that we could also lose due to + LIMIT_RELOAD_RELOAD_CLASS, but we don't check that + here. */ + + if (! CONSTANT_P (operand) + && (enum reg_class) this_alternative[i] != NO_REGS + && (PREFERRED_RELOAD_CLASS (operand, + (enum reg_class) this_alternative[i]) + == NO_REGS)) + bad = 1; + /* Alternative loses if it requires a type of reload not permitted for this insn. We can always reload SCRATCH and objects with a REG_UNUSED note. */ - if (GET_CODE (operand) != SCRATCH + else if (GET_CODE (operand) != SCRATCH && modified[i] != RELOAD_READ && no_output_reloads && ! find_reg_note (insn, REG_UNUSED, operand)) bad = 1; @@ -3464,27 +3430,11 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, && ! const_to_mem) bad = 1; - /* If we can't reload this value at all, reject this - alternative. Note that we could also lose due to - LIMIT_RELOAD_CLASS, but we don't check that - here. */ - - if (! CONSTANT_P (operand) - && (enum reg_class) this_alternative[i] != NO_REGS) - { - if (PREFERRED_RELOAD_CLASS - (operand, (enum reg_class) this_alternative[i]) - == NO_REGS) - reject = 600; - -#ifdef PREFERRED_OUTPUT_RELOAD_CLASS - if (operand_type[i] == RELOAD_FOR_OUTPUT - && PREFERRED_OUTPUT_RELOAD_CLASS - (operand, (enum reg_class) this_alternative[i]) - == NO_REGS) - reject = 600; +#ifdef DISPARAGE_RELOAD_CLASS + reject + += DISPARAGE_RELOAD_CLASS (operand, + (enum reg_class) this_alternative[i]); #endif - } /* We prefer to reload pseudos over reloading other things, since such reloads may be able to be eliminated later. @@ -3494,7 +3444,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, case where we are forcing a constant into memory and it will then win since we don't want to have a different alternative match then. */ - if (! (REG_P (operand) + if (! (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER) && GET_CODE (operand) != SCRATCH && ! (const_to_mem && constmemok)) @@ -3531,8 +3481,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, if (! win && ! did_match && this_alternative[i] != (int) NO_REGS && GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD - && reg_class_size [(int) preferred_class[i]] > 0 - && ! SMALL_REGISTER_CLASS_P (preferred_class[i])) + && reg_class_size[(int) preferred_class[i]] > 1) { if (! reg_class_subset_p (this_alternative[i], preferred_class[i])) @@ -3562,19 +3511,22 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, early_data = decompose (recog_data.operand[i]); - gcc_assert (modified[i] != RELOAD_READ); + if (modified[i] == RELOAD_READ) + abort (); if (this_alternative[i] == NO_REGS) { this_alternative_earlyclobber[i] = 0; - gcc_assert (this_insn_is_asm); - error_for_asm (this_insn, - "%<&%> constraint used with no register class"); + if (this_insn_is_asm) + error_for_asm (this_insn, + "`&' constraint used with no register class"); + else + abort (); } for (j = 0; j < noperands; j++) /* Is this an input operand or a memory ref? */ - if ((MEM_P (recog_data.operand[j]) + if ((GET_CODE (recog_data.operand[j]) == MEM || modified[j] != RELOAD_WRITE) && j != i /* Ignore things like match_operator operands. */ @@ -3588,10 +3540,10 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, && !immune_p (recog_data.operand[j], recog_data.operand[i], early_data)) { - /* If the output is in a non-empty few-regs class, + /* If the output is in a single-reg class, it's costly to reload it, so reload the input instead. */ - if (SMALL_REGISTER_CLASS_P (this_alternative[i]) - && (REG_P (recog_data.operand[j]) + if (reg_class_size[this_alternative[i]] == 1 + && (GET_CODE (recog_data.operand[j]) == REG || GET_CODE (recog_data.operand[j]) == SUBREG)) { losers++; @@ -3708,10 +3660,6 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, pref_or_nothing[commutative] = pref_or_nothing[commutative + 1]; pref_or_nothing[commutative + 1] = t; - t = address_reloaded[commutative]; - address_reloaded[commutative] = address_reloaded[commutative + 1]; - address_reloaded[commutative + 1] = t; - memcpy (constraints, recog_data.constraints, noperands * sizeof (char *)); goto try_swapped; @@ -3740,7 +3688,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, /* No alternative works with reloads?? */ if (insn_code_number >= 0) fatal_insn ("unable to generate reloads for:", insn); - error_for_asm (insn, "inconsistent operand constraints in an %<asm%>"); + error_for_asm (insn, "inconsistent operand constraints in an `asm'"); /* Avoid further trouble with this insn. */ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx); n_reloads = 0; @@ -3827,7 +3775,9 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, into registers are here changed into memory references. */ for (i = 0; i < noperands; i++) if (! goal_alternative_win[i] - && CONST_POOL_OK_P (recog_data.operand[i]) + && CONSTANT_P (recog_data.operand[i]) + /* force_const_mem does not accept HIGH. */ + && GET_CODE (recog_data.operand[i]) != HIGH && ((PREFERRED_RELOAD_CLASS (recog_data.operand[i], (enum reg_class) goal_alternative[i]) == NO_REGS) @@ -3844,27 +3794,6 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, goal_alternative_win[i] = 1; } - /* Likewise any invalid constants appearing as operand of a PLUS - that is to be reloaded. */ - for (i = 0; i < noperands; i++) - if (! goal_alternative_win[i] - && GET_CODE (recog_data.operand[i]) == PLUS - && CONST_POOL_OK_P (XEXP (recog_data.operand[i], 1)) - && (PREFERRED_RELOAD_CLASS (XEXP (recog_data.operand[i], 1), - (enum reg_class) goal_alternative[i]) - == NO_REGS) - && operand_mode[i] != VOIDmode) - { - rtx tem = force_const_mem (operand_mode[i], - XEXP (recog_data.operand[i], 1)); - tem = gen_rtx_PLUS (operand_mode[i], - XEXP (recog_data.operand[i], 0), tem); - - substed_operand[i] = recog_data.operand[i] - = find_reloads_toplev (tem, i, address_type[i], - ind_levels, 0, insn, NULL); - } - /* Record the values of the earlyclobber operands for the caller. */ if (goal_earlyclobber) for (i = 0; i < noperands; i++) @@ -3887,21 +3816,13 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, so we don't bother with it. It may not be worth doing. */ else if (goal_alternative_matched[i] == -1 && goal_alternative_offmemok[i] - && MEM_P (recog_data.operand[i])) + && GET_CODE (recog_data.operand[i]) == MEM) { - /* If the address to be reloaded is a VOIDmode constant, - use Pmode as mode of the reload register, as would have - been done by find_reloads_address. */ - enum machine_mode address_mode; - address_mode = GET_MODE (XEXP (recog_data.operand[i], 0)); - if (address_mode == VOIDmode) - address_mode = Pmode; - operand_reloadnum[i] = push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX, &XEXP (recog_data.operand[i], 0), (rtx*) 0, - base_reg_class (VOIDmode, MEM, SCRATCH), - address_mode, + MODE_BASE_REG_CLASS (VOIDmode), + GET_MODE (XEXP (recog_data.operand[i], 0)), VOIDmode, 0, 0, i, RELOAD_FOR_INPUT); rld[operand_reloadnum[i]].inc = GET_MODE_SIZE (GET_MODE (recog_data.operand[i])); @@ -3977,11 +3898,11 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, 0, 0, i, RELOAD_OTHER); operand_reloadnum[i] = output_reloadnum; } + else if (insn_code_number >= 0) + abort (); else { - gcc_assert (insn_code_number < 0); - error_for_asm (insn, "inconsistent operand constraints " - "in an %<asm%>"); + error_for_asm (insn, "inconsistent operand constraints in an `asm'"); /* Avoid further trouble with this insn. */ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx); n_reloads = 0; @@ -3990,7 +3911,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, } else if (goal_alternative_matched[i] < 0 && goal_alternative_matches[i] < 0 - && address_operand_reloaded[i] != 1 + && !address_operand_reloaded[i] && optimize) { /* For each non-matching operand that's a MEM or a pseudo-register @@ -4001,8 +3922,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, while (GET_CODE (operand) == SUBREG) operand = SUBREG_REG (operand); - if ((MEM_P (operand) - || (REG_P (operand) + if ((GET_CODE (operand) == MEM + || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER)) /* If this is only for an output, the optional reload would not actually cause us to use a register now, just note that @@ -4042,8 +3963,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, we then need to emit a USE and/or a CLOBBER so that reload inheritance will do the right thing. */ else if (replace - && (MEM_P (operand) - || (REG_P (operand) + && (GET_CODE (operand) == MEM + || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER && reg_renumber [REGNO (operand)] < 0))) { @@ -4051,7 +3972,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, while (GET_CODE (operand) == SUBREG) operand = SUBREG_REG (operand); - if (REG_P (operand)) + if (GET_CODE (operand) == REG) { if (modified[i] != RELOAD_WRITE) /* We mark the USE with QImode so that we recognize @@ -4078,8 +3999,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, while (GET_CODE (operand) == SUBREG) operand = SUBREG_REG (operand); - if ((MEM_P (operand) - || (REG_P (operand) + if ((GET_CODE (operand) == MEM + || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER)) && ((enum reg_class) goal_alternative[goal_alternative_matches[i]] != NO_REGS)) @@ -4102,7 +4023,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, { /* We only do this on the last pass through reload, because it is possible for some data (like reg_equiv_address) to be changed during - later passes. Moreover, we lose the opportunity to get a useful + later passes. Moreover, we loose the opportunity to get a useful reload_{in,out}_reg when we do these replacements. */ if (replace) @@ -4114,7 +4035,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, /* If we're replacing an operand with a LABEL_REF, we need to make sure that there's a REG_LABEL note attached to this instruction. */ - if (!JUMP_P (insn) + if (GET_CODE (insn) != JUMP_INSN && GET_CODE (substitution) == LABEL_REF && !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0))) REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, @@ -4154,7 +4075,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, for (i = 0; i < n_reloads; i++) if (rld[i].reg_rtx == 0 && rld[i].in != 0 - && REG_P (rld[i].in) + && GET_CODE (rld[i].in) == REG && rld[i].out == 0) { rld[i].reg_rtx @@ -4167,12 +4088,6 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, } #endif - /* If we detected error and replaced asm instruction by USE, forget about the - reloads. */ - if (GET_CODE (PATTERN (insn)) == USE - && GET_CODE (XEXP (PATTERN (insn), 0)) == CONST_INT) - n_reloads = 0; - /* Perhaps an output reload can be combined with another to reduce needs by one. */ if (!goal_earlyclobber) @@ -4442,9 +4357,10 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, do after the insn (such as for output addresses) are fine. */ if (no_input_reloads) for (i = 0; i < n_reloads; i++) - gcc_assert (rld[i].in == 0 - || rld[i].when_needed == RELOAD_FOR_OUTADDR_ADDRESS - || rld[i].when_needed == RELOAD_FOR_OUTPUT_ADDRESS); + if (rld[i].in != 0 + && rld[i].when_needed != RELOAD_FOR_OUTADDR_ADDRESS + && rld[i].when_needed != RELOAD_FOR_OUTPUT_ADDRESS) + abort (); #endif /* Compute reload_mode and reload_nregs. */ @@ -4464,7 +4380,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, for (i = 0; i < n_reloads; i++) if (rld[i].when_needed == RELOAD_FOR_INPUT && GET_CODE (PATTERN (insn)) == SET - && REG_P (SET_DEST (PATTERN (insn))) + && GET_CODE (SET_DEST (PATTERN (insn))) == REG && SET_SRC (PATTERN (insn)) == rld[i].in) { rtx dest = SET_DEST (PATTERN (insn)); @@ -4474,7 +4390,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, && TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno) && HARD_REGNO_MODE_OK (regno, rld[i].mode)) { - int nr = hard_regno_nregs[regno][rld[i].mode]; + int nr = HARD_REGNO_NREGS (regno, rld[i].mode); int ok = 1, nri; for (nri = 1; nri < nr; nri ++) @@ -4575,8 +4491,6 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type, x = mem; i = find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0), opnum, type, ind_levels, insn); - if (x != mem) - push_reg_equiv_alt_mem (regno, x); if (address_reloaded) *address_reloaded = i; } @@ -4595,36 +4509,35 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type, return tem; } - if (code == SUBREG && REG_P (SUBREG_REG (x))) + if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG) { - /* Check for SUBREG containing a REG that's equivalent to a - constant. If the constant has a known value, truncate it - right now. Similarly if we are extracting a single-word of a - multi-word constant. If the constant is symbolic, allow it - to be substituted normally. push_reload will strip the - subreg later. The constant must not be VOIDmode, because we - will lose the mode of the register (this should never happen - because one of the cases above should handle it). */ + /* Check for SUBREG containing a REG that's equivalent to a constant. + If the constant has a known value, truncate it right now. + Similarly if we are extracting a single-word of a multi-word + constant. If the constant is symbolic, allow it to be substituted + normally. push_reload will strip the subreg later. If the + constant is VOIDmode, abort because we will lose the mode of + the register (this should never happen because one of the cases + above should handle it). */ int regno = REGNO (SUBREG_REG (x)); rtx tem; if (subreg_lowpart_p (x) - && regno >= FIRST_PSEUDO_REGISTER - && reg_renumber[regno] < 0 + && regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 && reg_equiv_constant[regno] != 0 && (tem = gen_lowpart_common (GET_MODE (x), reg_equiv_constant[regno])) != 0) return tem; - if (regno >= FIRST_PSEUDO_REGISTER - && reg_renumber[regno] < 0 + if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 && reg_equiv_constant[regno] != 0) { tem = simplify_gen_subreg (GET_MODE (x), reg_equiv_constant[regno], GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x)); - gcc_assert (tem); + if (!tem) + abort (); return tem; } @@ -4641,7 +4554,7 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type, a wider mode if we have a paradoxical SUBREG. find_reloads will force a reload in that case. So we should not do anything here. */ - if (regno >= FIRST_PSEUDO_REGISTER + else if (regno >= FIRST_PSEUDO_REGISTER #ifdef LOAD_EXTEND_OP && (GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) @@ -4738,9 +4651,8 @@ maybe_memory_address_p (enum machine_mode mode, rtx ad, rtx *part) to determine if we may generate output reloads, and where to put USEs for pseudos that we have to replace with stack slots. - Value is one if this address is reloaded or replaced as a whole; it is - zero if the top level of this address was not reloaded or replaced, and - it is -1 if it may or may not have been reloaded or replaced. + Value is nonzero if this address is reloaded or replaced as a whole. + This is interesting to the caller if the address is an autoincrement. Note that there is no verification that the address will be valid after this routine does its work. Instead, we rely on the fact that the address @@ -4755,14 +4667,13 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, { int regno; int removed_and = 0; - int op_index; rtx tem; /* If the address is a register, see if it is a legitimate address and reload if not. We first handle the cases where we need not reload or where we must reload in a non-standard way. */ - if (REG_P (ad)) + if (GET_CODE (ad) == REG) { regno = REGNO (ad); @@ -4785,13 +4696,9 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, tem = make_memloc (ad, regno); if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0))) { - rtx orig = tem; - find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), &XEXP (tem, 0), opnum, ADDR_TYPE (type), ind_levels, insn); - if (tem != orig) - push_reg_equiv_alt_mem (regno, tem); } /* We can avoid a reload if the register's equivalent memory expression is valid as an indirect memory address. @@ -4800,9 +4707,9 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, if (ind_levels > 0 && strict_memory_address_p (mode, tem) - && (REG_P (XEXP (tem, 0)) + && (GET_CODE (XEXP (tem, 0)) == REG || (GET_CODE (XEXP (tem, 0)) == PLUS - && REG_P (XEXP (XEXP (tem, 0), 0)) + && GET_CODE (XEXP (XEXP (tem, 0), 0)) == REG && CONSTANT_P (XEXP (XEXP (tem, 0), 1))))) { /* TEM is not the same as what we'll be replacing the @@ -4833,12 +4740,12 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, subject of a CLOBBER in this insn. */ else if (regno < FIRST_PSEUDO_REGISTER - && regno_ok_for_base_p (regno, mode, MEM, SCRATCH) + && REGNO_MODE_OK_FOR_BASE_P (regno, mode) && ! regno_clobbered_p (regno, this_insn, mode, 0)) return 0; /* If we do not have one of the cases above, we must do the reload. */ - push_reload (ad, NULL_RTX, loc, (rtx*) 0, base_reg_class (mode, MEM, SCRATCH), + push_reload (ad, NULL_RTX, loc, (rtx*) 0, MODE_BASE_REG_CLASS (mode), GET_MODE (ad), VOIDmode, 0, 0, opnum, type); return 1; } @@ -4855,7 +4762,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, /* But first quickly dispose of a common case. */ if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT - && REG_P (XEXP (ad, 0)) + && GET_CODE (XEXP (ad, 0)) == REG && reg_equiv_constant[REGNO (XEXP (ad, 0))] == 0) return 0; @@ -4883,7 +4790,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, *memrefloc = copy_rtx (*memrefloc); XEXP (*memrefloc, 0) = ad; move_replacements (&ad, &XEXP (*memrefloc, 0)); - return -1; + return 1; } while (0); #endif @@ -4904,7 +4811,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, frame and stack pointers is not its initial value. In that case the pseudo will have been replaced by a MEM referring to the stack pointer. */ - if (MEM_P (ad)) + if (GET_CODE (ad) == MEM) { /* First ensure that the address in this MEM is valid. Then, unless indirect addresses are valid, reload the MEM into a register. */ @@ -4930,16 +4837,16 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, if (ind_levels == 0 || (GET_CODE (XEXP (tem, 0)) == SYMBOL_REF && ! indirect_symref_ok) - || MEM_P (XEXP (tem, 0)) - || ! (REG_P (XEXP (tem, 0)) + || GET_CODE (XEXP (tem, 0)) == MEM + || ! (GET_CODE (XEXP (tem, 0)) == REG || (GET_CODE (XEXP (tem, 0)) == PLUS - && REG_P (XEXP (XEXP (tem, 0), 0)) + && GET_CODE (XEXP (XEXP (tem, 0), 0)) == REG && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT))) { /* Must use TEM here, not AD, since it is the one that will have any subexpressions reloaded, if needed. */ push_reload (tem, NULL_RTX, loc, (rtx*) 0, - base_reg_class (mode, MEM, SCRATCH), GET_MODE (tem), + MODE_BASE_REG_CLASS (mode), GET_MODE (tem), VOIDmode, 0, 0, opnum, type); return ! removed_and; @@ -4954,12 +4861,10 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, targets (namely SH) we can also get too large displacements from big-endian corrections. */ else if (GET_CODE (ad) == PLUS - && REG_P (XEXP (ad, 0)) + && GET_CODE (XEXP (ad, 0)) == REG && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER - && GET_CODE (XEXP (ad, 1)) == CONST_INT - && regno_ok_for_base_p (REGNO (XEXP (ad, 0)), mode, PLUS, - CONST_INT)) - + && REG_MODE_OK_FOR_BASE_P (XEXP (ad, 0), mode) + && GET_CODE (XEXP (ad, 1)) == CONST_INT) { /* Unshare the MEM rtx so we can safely alter it. */ if (memrefloc) @@ -4987,8 +4892,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, /* If the sum of two regs is not necessarily valid, reload the sum into a base reg. That will at least work. */ - find_reloads_address_part (ad, loc, - base_reg_class (mode, MEM, SCRATCH), + find_reloads_address_part (ad, loc, MODE_BASE_REG_CLASS (mode), Pmode, opnum, type, ind_levels); } return ! removed_and; @@ -5008,9 +4912,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, Handle all base registers here, not just fp/ap/sp, because on some targets (namely SPARC) we can also get invalid addresses from preventive - subreg big-endian corrections made by find_reloads_toplev. We - can also get expressions involving LO_SUM (rather than PLUS) from - find_reloads_subreg_address. + subreg big-endian corrections made by find_reloads_toplev. If we decide to do something, it must be that `double_reg_address_ok' is true. We generate a reload of the base register + constant and @@ -5018,69 +4920,62 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, This is safe because we know the address isn't shared. We check for the base register as both the first and second operand of - the innermost PLUS and/or LO_SUM. */ - - for (op_index = 0; op_index < 2; ++op_index) + the innermost PLUS. */ + + else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT + && GET_CODE (XEXP (ad, 0)) == PLUS + && GET_CODE (XEXP (XEXP (ad, 0), 0)) == REG + && REGNO (XEXP (XEXP (ad, 0), 0)) < FIRST_PSEUDO_REGISTER + && (REG_MODE_OK_FOR_BASE_P (XEXP (XEXP (ad, 0), 0), mode) + || XEXP (XEXP (ad, 0), 0) == frame_pointer_rtx +#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM + || XEXP (XEXP (ad, 0), 0) == hard_frame_pointer_rtx +#endif +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + || XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx +#endif + || XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx) + && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 1))) { - rtx operand, addend; - enum rtx_code inner_code; - - if (GET_CODE (ad) != PLUS) - continue; + *loc = ad = gen_rtx_PLUS (GET_MODE (ad), + plus_constant (XEXP (XEXP (ad, 0), 0), + INTVAL (XEXP (ad, 1))), + XEXP (XEXP (ad, 0), 1)); + find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0), + MODE_BASE_REG_CLASS (mode), + GET_MODE (ad), opnum, type, ind_levels); + find_reloads_address_1 (mode, XEXP (ad, 1), 1, &XEXP (ad, 1), opnum, + type, 0, insn); - inner_code = GET_CODE (XEXP (ad, 0)); - if (!(GET_CODE (ad) == PLUS - && GET_CODE (XEXP (ad, 1)) == CONST_INT - && (inner_code == PLUS || inner_code == LO_SUM))) - continue; - - operand = XEXP (XEXP (ad, 0), op_index); - if (!REG_P (operand) || REGNO (operand) >= FIRST_PSEUDO_REGISTER) - continue; - - addend = XEXP (XEXP (ad, 0), 1 - op_index); + return 0; + } - if ((regno_ok_for_base_p (REGNO (operand), mode, inner_code, - GET_CODE (addend)) - || operand == frame_pointer_rtx + else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT + && GET_CODE (XEXP (ad, 0)) == PLUS + && GET_CODE (XEXP (XEXP (ad, 0), 1)) == REG + && REGNO (XEXP (XEXP (ad, 0), 1)) < FIRST_PSEUDO_REGISTER + && (REG_MODE_OK_FOR_BASE_P (XEXP (XEXP (ad, 0), 1), mode) + || XEXP (XEXP (ad, 0), 1) == frame_pointer_rtx #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM - || operand == hard_frame_pointer_rtx + || XEXP (XEXP (ad, 0), 1) == hard_frame_pointer_rtx #endif #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - || operand == arg_pointer_rtx + || XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx #endif - || operand == stack_pointer_rtx) - && ! maybe_memory_address_p (mode, ad, - &XEXP (XEXP (ad, 0), 1 - op_index))) - { - rtx offset_reg; - enum reg_class cls; - - offset_reg = plus_constant (operand, INTVAL (XEXP (ad, 1))); - - /* Form the adjusted address. */ - if (GET_CODE (XEXP (ad, 0)) == PLUS) - ad = gen_rtx_PLUS (GET_MODE (ad), - op_index == 0 ? offset_reg : addend, - op_index == 0 ? addend : offset_reg); - else - ad = gen_rtx_LO_SUM (GET_MODE (ad), - op_index == 0 ? offset_reg : addend, - op_index == 0 ? addend : offset_reg); - *loc = ad; - - cls = base_reg_class (mode, MEM, GET_CODE (addend)); - find_reloads_address_part (XEXP (ad, op_index), - &XEXP (ad, op_index), cls, - GET_MODE (ad), opnum, type, ind_levels); - find_reloads_address_1 (mode, - XEXP (ad, 1 - op_index), 1, GET_CODE (ad), - GET_CODE (XEXP (ad, op_index)), - &XEXP (ad, 1 - op_index), opnum, - type, 0, insn); + || XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx) + && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 0))) + { + *loc = ad = gen_rtx_PLUS (GET_MODE (ad), + XEXP (XEXP (ad, 0), 0), + plus_constant (XEXP (XEXP (ad, 0), 1), + INTVAL (XEXP (ad, 1)))); + find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1), + MODE_BASE_REG_CLASS (mode), + GET_MODE (ad), opnum, type, ind_levels); + find_reloads_address_1 (mode, XEXP (ad, 0), 1, &XEXP (ad, 0), opnum, + type, 0, insn); - return 0; - } + return 0; } /* See if address becomes valid when an eliminable register @@ -5121,13 +5016,13 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, loc = &XEXP (*loc, 0); } - find_reloads_address_part (ad, loc, base_reg_class (mode, MEM, SCRATCH), + find_reloads_address_part (ad, loc, MODE_BASE_REG_CLASS (mode), Pmode, opnum, type, ind_levels); return ! removed_and; } - return find_reloads_address_1 (mode, ad, 0, MEM, SCRATCH, loc, opnum, type, - ind_levels, insn); + return find_reloads_address_1 (mode, ad, 0, loc, opnum, type, ind_levels, + insn); } /* Find all pseudo regs appearing in AD @@ -5272,12 +5167,12 @@ subst_indexed_address (rtx addr) { /* Try to find a register to replace. */ op0 = XEXP (addr, 0), op1 = XEXP (addr, 1), op2 = 0; - if (REG_P (op0) + if (GET_CODE (op0) == REG && (regno = REGNO (op0)) >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 && reg_equiv_constant[regno] != 0) op0 = reg_equiv_constant[regno]; - else if (REG_P (op1) + else if (GET_CODE (op1) == REG && (regno = REGNO (op1)) >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 && reg_equiv_constant[regno] != 0) @@ -5339,11 +5234,7 @@ update_auto_inc_notes (rtx insn ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED, CONTEXT = 1 means we are considering regs as index regs, = 0 means we are considering them as base regs. - OUTER_CODE is the code of the enclosing RTX, typically a MEM, a PLUS, - or an autoinc code. - If CONTEXT == 0 and OUTER_CODE is a PLUS or LO_SUM, then INDEX_CODE - is the code of the index part of the address. Otherwise, pass SCRATCH - for this argument. + OPNUM and TYPE specify the purpose of any reloads made. IND_LEVELS says how many levels of indirect addressing are @@ -5358,29 +5249,15 @@ update_auto_inc_notes (rtx insn ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED, occurs as part of an address. Also, this is not fully machine-customizable; it works for machines such as VAXen and 68000's and 32000's, but other possible machines - could have addressing modes that this does not handle right. - If you add push_reload calls here, you need to make sure gen_reload - handles those cases gracefully. */ + could have addressing modes that this does not handle right. */ static int find_reloads_address_1 (enum machine_mode mode, rtx x, int context, - enum rtx_code outer_code, enum rtx_code index_code, rtx *loc, int opnum, enum reload_type type, int ind_levels, rtx insn) { -#define REG_OK_FOR_CONTEXT(CONTEXT, REGNO, MODE, OUTER, INDEX) \ - ((CONTEXT) == 0 \ - ? regno_ok_for_base_p (REGNO, MODE, OUTER, INDEX) \ - : REGNO_OK_FOR_INDEX_P (REGNO)) - - enum reg_class context_reg_class; RTX_CODE code = GET_CODE (x); - if (context == 1) - context_reg_class = INDEX_REG_CLASS; - else - context_reg_class = base_reg_class (mode, outer_code, index_code); - switch (code) { case PLUS: @@ -5420,15 +5297,15 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, GET_MODE (orig_op1)))); } /* Plus in the index register may be created only as a result of - register rematerialization for expression like &localvar*4. Reload it. + register remateralization for expression like &localvar*4. Reload it. It may be possible to combine the displacement on the outer level, but it is probably not worthwhile to do so. */ - if (context == 1) + if (context) { find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0), opnum, ADDR_TYPE (type), ind_levels, insn); push_reload (*loc, NULL_RTX, loc, (rtx*) 0, - context_reg_class, + (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); return 1; } @@ -5436,90 +5313,74 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE || code0 == ZERO_EXTEND || code1 == MEM) { - find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH, - &XEXP (x, 0), opnum, type, ind_levels, - insn); - find_reloads_address_1 (mode, orig_op1, 0, PLUS, code0, - &XEXP (x, 1), opnum, type, ind_levels, - insn); + find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum, + type, ind_levels, insn); + find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum, + type, ind_levels, insn); } else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE || code1 == ZERO_EXTEND || code0 == MEM) { - find_reloads_address_1 (mode, orig_op0, 0, PLUS, code1, - &XEXP (x, 0), opnum, type, ind_levels, - insn); - find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH, - &XEXP (x, 1), opnum, type, ind_levels, - insn); + find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum, + type, ind_levels, insn); + find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum, + type, ind_levels, insn); } else if (code0 == CONST_INT || code0 == CONST || code0 == SYMBOL_REF || code0 == LABEL_REF) - find_reloads_address_1 (mode, orig_op1, 0, PLUS, code0, - &XEXP (x, 1), opnum, type, ind_levels, - insn); + find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum, + type, ind_levels, insn); else if (code1 == CONST_INT || code1 == CONST || code1 == SYMBOL_REF || code1 == LABEL_REF) - find_reloads_address_1 (mode, orig_op0, 0, PLUS, code1, - &XEXP (x, 0), opnum, type, ind_levels, - insn); + find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum, + type, ind_levels, insn); else if (code0 == REG && code1 == REG) { - if (REGNO_OK_FOR_INDEX_P (REGNO (op0)) - && regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG)) + if (REG_OK_FOR_INDEX_P (op0) + && REG_MODE_OK_FOR_BASE_P (op1, mode)) return 0; - else if (REGNO_OK_FOR_INDEX_P (REGNO (op1)) - && regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG)) + else if (REG_OK_FOR_INDEX_P (op1) + && REG_MODE_OK_FOR_BASE_P (op0, mode)) return 0; - else if (regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG)) - find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH, - &XEXP (x, 0), opnum, type, ind_levels, - insn); - else if (regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG)) - find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH, - &XEXP (x, 1), opnum, type, ind_levels, - insn); - else if (REGNO_OK_FOR_INDEX_P (REGNO (op1))) - find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG, - &XEXP (x, 0), opnum, type, ind_levels, - insn); - else if (REGNO_OK_FOR_INDEX_P (REGNO (op0))) - find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG, - &XEXP (x, 1), opnum, type, ind_levels, - insn); + else if (REG_MODE_OK_FOR_BASE_P (op1, mode)) + find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum, + type, ind_levels, insn); + else if (REG_MODE_OK_FOR_BASE_P (op0, mode)) + find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum, + type, ind_levels, insn); + else if (REG_OK_FOR_INDEX_P (op1)) + find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum, + type, ind_levels, insn); + else if (REG_OK_FOR_INDEX_P (op0)) + find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum, + type, ind_levels, insn); else { - find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH, - &XEXP (x, 0), opnum, type, ind_levels, - insn); - find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG, - &XEXP (x, 1), opnum, type, ind_levels, - insn); + find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum, + type, ind_levels, insn); + find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum, + type, ind_levels, insn); } } else if (code0 == REG) { - find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH, - &XEXP (x, 0), opnum, type, ind_levels, - insn); - find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG, - &XEXP (x, 1), opnum, type, ind_levels, - insn); + find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum, + type, ind_levels, insn); + find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum, + type, ind_levels, insn); } else if (code1 == REG) { - find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH, - &XEXP (x, 1), opnum, type, ind_levels, - insn); - find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG, - &XEXP (x, 0), opnum, type, ind_levels, - insn); + find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum, + type, ind_levels, insn); + find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum, + type, ind_levels, insn); } } @@ -5530,9 +5391,6 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, { rtx op0 = XEXP (x, 0); rtx op1 = XEXP (x, 1); - enum rtx_code index_code; - int regno; - int reloadnum; if (GET_CODE (op1) != PLUS && GET_CODE (op1) != MINUS) return 0; @@ -5541,87 +5399,79 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, where a base register is {inc,dec}remented by the contents of another register or by a constant value. Thus, these operands must match. */ - gcc_assert (op0 == XEXP (op1, 0)); + if (op0 != XEXP (op1, 0)) + abort (); /* Require index register (or constant). Let's just handle the register case in the meantime... If the target allows auto-modify by a constant then we could try replacing a pseudo - register with its equivalent constant where applicable. - - If we later decide to reload the whole PRE_MODIFY or - POST_MODIFY, inc_for_reload might clobber the reload register - before reading the index. The index register might therefore - need to live longer than a TYPE reload normally would, so be - conservative and class it as RELOAD_OTHER. */ + register with its equivalent constant where applicable. */ if (REG_P (XEXP (op1, 1))) if (!REGNO_OK_FOR_INDEX_P (REGNO (XEXP (op1, 1)))) - find_reloads_address_1 (mode, XEXP (op1, 1), 1, code, SCRATCH, - &XEXP (op1, 1), opnum, RELOAD_OTHER, - ind_levels, insn); - - gcc_assert (REG_P (XEXP (op1, 0))); - - regno = REGNO (XEXP (op1, 0)); - index_code = GET_CODE (XEXP (op1, 1)); + find_reloads_address_1 (mode, XEXP (op1, 1), 1, &XEXP (op1, 1), + opnum, type, ind_levels, insn); - /* A register that is incremented cannot be constant! */ - gcc_assert (regno < FIRST_PSEUDO_REGISTER - || reg_equiv_constant[regno] == 0); - - /* Handle a register that is equivalent to a memory location - which cannot be addressed directly. */ - if (reg_equiv_memory_loc[regno] != 0 - && (reg_equiv_address[regno] != 0 - || num_not_at_initial_offset)) + if (REG_P (XEXP (op1, 0))) { - rtx tem = make_memloc (XEXP (x, 0), regno); - - if (reg_equiv_address[regno] - || ! rtx_equal_p (tem, reg_equiv_mem[regno])) + int regno = REGNO (XEXP (op1, 0)); + int reloadnum; + + /* A register that is incremented cannot be constant! */ + if (regno >= FIRST_PSEUDO_REGISTER + && reg_equiv_constant[regno] != 0) + abort (); + + /* Handle a register that is equivalent to a memory location + which cannot be addressed directly. */ + if (reg_equiv_memory_loc[regno] != 0 + && (reg_equiv_address[regno] != 0 + || num_not_at_initial_offset)) { - rtx orig = tem; - - /* First reload the memory location's address. - We can't use ADDR_TYPE (type) here, because we need to - write back the value after reading it, hence we actually - need two registers. */ - find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), - &XEXP (tem, 0), opnum, - RELOAD_OTHER, - ind_levels, insn); + rtx tem = make_memloc (XEXP (x, 0), regno); + + if (reg_equiv_address[regno] + || ! rtx_equal_p (tem, reg_equiv_mem[regno])) + { + /* First reload the memory location's address. + We can't use ADDR_TYPE (type) here, because we need to + write back the value after reading it, hence we actually + need two registers. */ + find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), + &XEXP (tem, 0), opnum, + RELOAD_OTHER, + ind_levels, insn); + + /* Then reload the memory location into a base + register. */ + reloadnum = push_reload (tem, tem, &XEXP (x, 0), + &XEXP (op1, 0), + MODE_BASE_REG_CLASS (mode), + GET_MODE (x), GET_MODE (x), 0, + 0, opnum, RELOAD_OTHER); + + update_auto_inc_notes (this_insn, regno, reloadnum); + return 0; + } + } - if (tem != orig) - push_reg_equiv_alt_mem (regno, tem); + if (reg_renumber[regno] >= 0) + regno = reg_renumber[regno]; - /* Then reload the memory location into a base - register. */ - reloadnum = push_reload (tem, tem, &XEXP (x, 0), - &XEXP (op1, 0), - base_reg_class (mode, code, - index_code), - GET_MODE (x), GET_MODE (x), 0, - 0, opnum, RELOAD_OTHER); + /* We require a base register here... */ + if (!REGNO_MODE_OK_FOR_BASE_P (regno, GET_MODE (x))) + { + reloadnum = push_reload (XEXP (op1, 0), XEXP (x, 0), + &XEXP (op1, 0), &XEXP (x, 0), + MODE_BASE_REG_CLASS (mode), + GET_MODE (x), GET_MODE (x), 0, 0, + opnum, RELOAD_OTHER); update_auto_inc_notes (this_insn, regno, reloadnum); return 0; } } - - if (reg_renumber[regno] >= 0) - regno = reg_renumber[regno]; - - /* We require a base register here... */ - if (!regno_ok_for_base_p (regno, GET_MODE (x), code, index_code)) - { - reloadnum = push_reload (XEXP (op1, 0), XEXP (x, 0), - &XEXP (op1, 0), &XEXP (x, 0), - base_reg_class (mode, code, index_code), - GET_MODE (x), GET_MODE (x), 0, 0, - opnum, RELOAD_OTHER); - - update_auto_inc_notes (this_insn, regno, reloadnum); - return 0; - } + else + abort (); } return 0; @@ -5629,15 +5479,16 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, case POST_DEC: case PRE_INC: case PRE_DEC: - if (REG_P (XEXP (x, 0))) + if (GET_CODE (XEXP (x, 0)) == REG) { int regno = REGNO (XEXP (x, 0)); int value = 0; rtx x_orig = x; /* A register that is incremented cannot be constant! */ - gcc_assert (regno < FIRST_PSEUDO_REGISTER - || reg_equiv_constant[regno] == 0); + if (regno >= FIRST_PSEUDO_REGISTER + && reg_equiv_constant[regno] != 0) + abort (); /* Handle a register that is equivalent to a memory location which cannot be addressed directly. */ @@ -5648,8 +5499,6 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, if (reg_equiv_address[regno] || ! rtx_equal_p (tem, reg_equiv_mem[regno])) { - rtx orig = tem; - /* First reload the memory location's address. We can't use ADDR_TYPE (type) here, because we need to write back the value after reading it, hence we actually @@ -5657,8 +5506,6 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), &XEXP (tem, 0), opnum, type, ind_levels, insn); - if (tem != orig) - push_reg_equiv_alt_mem (regno, tem); /* Put this inside a new increment-expression. */ x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem); /* Proceed to reload that, as if it contained a register. */ @@ -5678,9 +5525,9 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, if (reg_renumber[regno] >= 0) regno = reg_renumber[regno]; - if (regno >= FIRST_PSEUDO_REGISTER - || !REG_OK_FOR_CONTEXT (context, regno, mode, outer_code, - index_code)) + if ((regno >= FIRST_PSEUDO_REGISTER + || !(context ? REGNO_OK_FOR_INDEX_P (regno) + : REGNO_MODE_OK_FOR_BASE_P (regno, mode)))) { int reloadnum; @@ -5692,11 +5539,11 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, memory location, since this will make it harder to reuse address reloads, and increases register pressure. Also don't do this if we can probably update x directly. */ - rtx equiv = (MEM_P (XEXP (x, 0)) + rtx equiv = (GET_CODE (XEXP (x, 0)) == MEM ? XEXP (x, 0) : reg_equiv_mem[regno]); int icode = (int) add_optab->handlers[(int) Pmode].insn_code; - if (insn && NONJUMP_INSN_P (insn) && equiv + if (insn && GET_CODE (insn) == INSN && equiv && memory_operand (equiv, GET_MODE (equiv)) #ifdef HAVE_cc0 && ! sets_cc0_p (PATTERN (insn)) @@ -5716,7 +5563,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, x = XEXP (x, 0); reloadnum = push_reload (x, x, loc, loc, - context_reg_class, + (context ? INDEX_REG_CLASS : + MODE_BASE_REG_CLASS (mode)), GET_MODE (x), GET_MODE (x), 0, 0, opnum, RELOAD_OTHER); } @@ -5724,7 +5572,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, { reloadnum = push_reload (x, NULL_RTX, loc, (rtx*) 0, - context_reg_class, + (context ? INDEX_REG_CLASS : + MODE_BASE_REG_CLASS (mode)), GET_MODE (x), GET_MODE (x), 0, 0, opnum, type); rld[reloadnum].inc @@ -5739,7 +5588,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, return value; } - else if (MEM_P (XEXP (x, 0))) + else if (GET_CODE (XEXP (x, 0)) == MEM) { /* This is probably the result of a substitution, by eliminate_regs, of an equivalent address for a pseudo that was not allocated to a @@ -5764,7 +5613,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, opnum, type, ind_levels, insn); reloadnum = push_reload (x, NULL_RTX, loc, (rtx*) 0, - context_reg_class, + (context ? INDEX_REG_CLASS : + MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); rld[reloadnum].inc = find_inc_amount (PATTERN (this_insn), XEXP (x, 0)); @@ -5777,24 +5627,6 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, } return 0; - case TRUNCATE: - case SIGN_EXTEND: - case ZERO_EXTEND: - /* Look for parts to reload in the inner expression and reload them - too, in addition to this operation. Reloading all inner parts in - addition to this one shouldn't be necessary, but at this point, - we don't know if we can possibly omit any part that *can* be - reloaded. Targets that are better off reloading just either part - (or perhaps even a different part of an outer expression), should - define LEGITIMIZE_RELOAD_ADDRESS. */ - find_reloads_address_1 (GET_MODE (XEXP (x, 0)), XEXP (x, 0), - context, code, SCRATCH, &XEXP (x, 0), opnum, - type, ind_levels, insn); - push_reload (x, NULL_RTX, loc, (rtx*) 0, - context_reg_class, - GET_MODE (x), VOIDmode, 0, 0, opnum, type); - return 1; - case MEM: /* This is probably the result of a substitution, by eliminate_regs, of an equivalent address for a pseudo that was not allocated to a hard @@ -5811,7 +5643,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0), opnum, ADDR_TYPE (type), ind_levels, insn); push_reload (*loc, NULL_RTX, loc, (rtx*) 0, - context_reg_class, + (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); return 1; @@ -5822,7 +5654,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, if (reg_equiv_constant[regno] != 0) { find_reloads_address_part (reg_equiv_constant[regno], loc, - context_reg_class, + (context ? INDEX_REG_CLASS : + MODE_BASE_REG_CLASS (mode)), GET_MODE (x), opnum, type, ind_levels); return 1; } @@ -5832,7 +5665,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, if (reg_equiv_mem[regno] != 0) { push_reload (reg_equiv_mem[regno], NULL_RTX, loc, (rtx*) 0, - context_reg_class, + (context ? INDEX_REG_CLASS : + MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); return 1; } @@ -5849,20 +5683,18 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0), opnum, ADDR_TYPE (type), ind_levels, insn); - if (x != tem) - push_reg_equiv_alt_mem (regno, x); } } if (reg_renumber[regno] >= 0) regno = reg_renumber[regno]; - if (regno >= FIRST_PSEUDO_REGISTER - || !REG_OK_FOR_CONTEXT (context, regno, mode, outer_code, - index_code)) + if ((regno >= FIRST_PSEUDO_REGISTER + || !(context ? REGNO_OK_FOR_INDEX_P (regno) + : REGNO_MODE_OK_FOR_BASE_P (regno, mode)))) { push_reload (x, NULL_RTX, loc, (rtx*) 0, - context_reg_class, + (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); return 1; } @@ -5874,7 +5706,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, if (regno_clobbered_p (regno, this_insn, GET_MODE (x), 0)) { push_reload (x, NULL_RTX, loc, (rtx*) 0, - context_reg_class, + (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); return 1; } @@ -5882,7 +5714,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, return 0; case SUBREG: - if (REG_P (SUBREG_REG (x))) + if (GET_CODE (SUBREG_REG (x)) == REG) { /* If this is a SUBREG of a hard register and the resulting register is of the wrong class, reload the whole SUBREG. This avoids @@ -5891,11 +5723,12 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, { int regno ATTRIBUTE_UNUSED = subreg_regno (x); - if (!REG_OK_FOR_CONTEXT (context, regno, mode, outer_code, - index_code)) + if (! (context ? REGNO_OK_FOR_INDEX_P (regno) + : REGNO_MODE_OK_FOR_BASE_P (regno, mode))) { push_reload (x, NULL_RTX, loc, (rtx*) 0, - context_reg_class, + (context ? INDEX_REG_CLASS : + MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); return 1; } @@ -5904,12 +5737,12 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, is larger than the class size, then reload the whole SUBREG. */ else { - enum reg_class class = context_reg_class; + enum reg_class class = (context ? INDEX_REG_CLASS + : MODE_BASE_REG_CLASS (mode)); if ((unsigned) CLASS_MAX_NREGS (class, GET_MODE (SUBREG_REG (x))) > reg_class_size[class]) { - x = find_reloads_subreg_address (x, 0, opnum, - ADDR_TYPE (type), + x = find_reloads_subreg_address (x, 0, opnum, type, ind_levels, insn); push_reload (x, NULL_RTX, loc, (rtx*) 0, class, GET_MODE (x), VOIDmode, 0, 0, opnum, type); @@ -5930,14 +5763,11 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') - /* Pass SCRATCH for INDEX_CODE, since CODE can never be a PLUS once - we get here. */ - find_reloads_address_1 (mode, XEXP (x, i), context, code, SCRATCH, - &XEXP (x, i), opnum, type, ind_levels, insn); + find_reloads_address_1 (mode, XEXP (x, i), context, &XEXP (x, i), + opnum, type, ind_levels, insn); } } -#undef REG_OK_FOR_CONTEXT return 0; } @@ -6038,9 +5868,6 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum, unsigned outer_size = GET_MODE_SIZE (GET_MODE (x)); unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))); int offset; - rtx orig = tem; - enum machine_mode orig_mode = GET_MODE (orig); - int reloaded; /* For big-endian paradoxical subregs, SUBREG_BYTE does not hold the correct (negative) byte offset. */ @@ -6055,7 +5882,7 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum, /* If this was a paradoxical subreg that we replaced, the resulting memory must be sufficiently aligned to allow us to widen the mode of the memory. */ - if (outer_size > inner_size) + if (outer_size > inner_size && STRICT_ALIGNMENT) { rtx base; @@ -6067,37 +5894,15 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum, return x; base = XEXP (base, 0); } - if (!REG_P (base) + if (GET_CODE (base) != REG || (REGNO_POINTER_ALIGN (REGNO (base)) < outer_size * BITS_PER_UNIT)) return x; } - reloaded = find_reloads_address (GET_MODE (tem), &tem, - XEXP (tem, 0), &XEXP (tem, 0), - opnum, type, ind_levels, insn); - /* ??? Do we need to handle nonzero offsets somehow? */ - if (!offset && tem != orig) - push_reg_equiv_alt_mem (regno, tem); - - /* For some processors an address may be valid in the - original mode but not in a smaller mode. For - example, ARM accepts a scaled index register in - SImode but not in HImode. find_reloads_address - assumes that we pass it a valid address, and doesn't - force a reload. This will probably be fine if - find_reloads_address finds some reloads. But if it - doesn't find any, then we may have just converted a - valid address into an invalid one. Check for that - here. */ - if (reloaded != 1 - && strict_memory_address_p (orig_mode, XEXP (tem, 0)) - && !strict_memory_address_p (GET_MODE (tem), - XEXP (tem, 0))) - push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0, - base_reg_class (GET_MODE (tem), MEM, SCRATCH), - GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0, - opnum, type); + find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), + &XEXP (tem, 0), opnum, ADDR_TYPE (type), + ind_levels, insn); /* If this is not a toplevel operand, find_reloads doesn't see this substitution. We have to emit a USE of the pseudo so @@ -6147,9 +5952,10 @@ subst_reloads (rtx insn) for (check_regno = 0; check_regno < max_regno; check_regno++) { #define CHECK_MODF(ARRAY) \ - gcc_assert (!ARRAY[check_regno] \ - || !loc_mentioned_in_p (r->where, \ - ARRAY[check_regno])) + if (ARRAY[check_regno] \ + && loc_mentioned_in_p (r->where, \ + ARRAY[check_regno])) \ + abort () CHECK_MODF (reg_equiv_constant); CHECK_MODF (reg_equiv_memory_loc); @@ -6163,13 +5969,10 @@ subst_reloads (rtx insn) REG_LABEL note to indicate to flow which label this register refers to. */ if (GET_CODE (*r->where) == LABEL_REF - && JUMP_P (insn)) - { - REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, - XEXP (*r->where, 0), - REG_NOTES (insn)); - JUMP_LABEL (insn) = XEXP (*r->where, 0); - } + && GET_CODE (insn) == JUMP_INSN) + REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, + XEXP (*r->where, 0), + REG_NOTES (insn)); /* Encapsulate RELOADREG so its machine mode matches what used to be there. Note that gen_lowpart_common will @@ -6207,8 +6010,8 @@ subst_reloads (rtx insn) *r->where = reloadreg; } /* If reload got no reg and isn't optional, something's wrong. */ - else - gcc_assert (rld[r->what].optional); + else if (! rld[r->what].optional) + abort (); } } @@ -6220,7 +6023,8 @@ copy_replacements (rtx x, rtx y) { /* We can't support X being a SUBREG because we might then need to know its location if something inside it was replaced. */ - gcc_assert (GET_CODE (x) != SUBREG); + if (GET_CODE (x) == SUBREG) + abort (); copy_replacements_1 (&x, &y, n_replacements); } @@ -6312,7 +6116,7 @@ find_replacement (rtx *loc) ??? Is it actually still ever a SUBREG? If so, why? */ - if (REG_P (reloadreg)) + if (GET_CODE (reloadreg) == REG) return gen_rtx_REG (GET_MODE (*loc), (REGNO (reloadreg) + subreg_regno_offset (REGNO (SUBREG_REG (*loc)), @@ -6360,7 +6164,7 @@ find_replacement (rtx *loc) This is similar to refers_to_regno_p in rtlanal.c except that we look at equivalences for pseudos that didn't get hard registers. */ -static int +int refers_to_regno_for_reload_p (unsigned int regno, unsigned int endregno, rtx x, rtx *loc) { @@ -6389,25 +6193,27 @@ refers_to_regno_for_reload_p (unsigned int regno, unsigned int endregno, reg_equiv_memory_loc[r], (rtx*) 0); - gcc_assert (reg_equiv_constant[r] || reg_equiv_invariant[r]); - return 0; + if (reg_equiv_constant[r]) + return 0; + + abort (); } return (endregno > r && regno < r + (r < FIRST_PSEUDO_REGISTER - ? hard_regno_nregs[r][GET_MODE (x)] + ? HARD_REGNO_NREGS (r, GET_MODE (x)) : 1)); case SUBREG: /* If this is a SUBREG of a hard reg, we can see exactly which registers are being modified. Otherwise, handle normally. */ - if (REG_P (SUBREG_REG (x)) + if (GET_CODE (SUBREG_REG (x)) == REG && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER) { unsigned int inner_regno = subreg_regno (x); unsigned int inner_endregno = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER - ? hard_regno_nregs[inner_regno][GET_MODE (x)] : 1); + ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); return endregno > inner_regno && regno < inner_endregno; } @@ -6421,14 +6227,14 @@ refers_to_regno_for_reload_p (unsigned int regno, unsigned int endregno, treat each word individually. */ && ((GET_CODE (SET_DEST (x)) == SUBREG && loc != &SUBREG_REG (SET_DEST (x)) - && REG_P (SUBREG_REG (SET_DEST (x))) + && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG && REGNO (SUBREG_REG (SET_DEST (x))) >= FIRST_PSEUDO_REGISTER && refers_to_regno_for_reload_p (regno, endregno, SUBREG_REG (SET_DEST (x)), loc)) /* If the output is an earlyclobber operand, this is a conflict. */ - || ((!REG_P (SET_DEST (x)) + || ((GET_CODE (SET_DEST (x)) != REG || earlyclobber_operand_p (SET_DEST (x))) && refers_to_regno_for_reload_p (regno, endregno, SET_DEST (x), loc)))) @@ -6489,14 +6295,12 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in) /* Overly conservative. */ if (GET_CODE (x) == STRICT_LOW_PART - || GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC) + || GET_RTX_CLASS (GET_CODE (x)) == 'a') x = XEXP (x, 0); /* If either argument is a constant, then modifying X can not affect IN. */ if (CONSTANT_P (x) || CONSTANT_P (in)) return 0; - else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM) - return refers_to_mem_for_reload_p (in); else if (GET_CODE (x) == SUBREG) { regno = REGNO (SUBREG_REG (x)); @@ -6506,7 +6310,7 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in) SUBREG_BYTE (x), GET_MODE (x)); } - else if (REG_P (x)) + else if (GET_CODE (x) == REG) { regno = REGNO (x); @@ -6517,27 +6321,26 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in) { if (reg_equiv_memory_loc[regno]) return refers_to_mem_for_reload_p (in); - gcc_assert (reg_equiv_constant[regno]); - return 0; + else if (reg_equiv_constant[regno]) + return 0; + abort (); } } - else if (MEM_P (x)) + else if (GET_CODE (x) == MEM) return refers_to_mem_for_reload_p (in); else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC || GET_CODE (x) == CC0) return reg_mentioned_p (x, in); - else + else if (GET_CODE (x) == PLUS) { - gcc_assert (GET_CODE (x) == PLUS); - /* We actually want to know if X is mentioned somewhere inside IN. We must not say that (plus (sp) (const_int 124)) is in (plus (sp) (const_int 64)), since that can lead to incorrect reload allocation when spuriously changing a RELOAD_FOR_OUTPUT_ADDRESS into a RELOAD_OTHER on behalf of another RELOAD_OTHER. */ - while (MEM_P (in)) + while (GET_CODE (in) == MEM) in = XEXP (in, 0); - if (REG_P (in)) + if (GET_CODE (in) == REG) return 0; else if (GET_CODE (in) == PLUS) return (reg_overlap_mentioned_for_reload_p (x, XEXP (in, 0)) @@ -6545,9 +6348,11 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in) else return (reg_overlap_mentioned_for_reload_p (XEXP (x, 0), in) || reg_overlap_mentioned_for_reload_p (XEXP (x, 1), in)); } + else + abort (); endregno = regno + (regno < FIRST_PSEUDO_REGISTER - ? hard_regno_nregs[regno][GET_MODE (x)] : 1); + ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0); } @@ -6555,23 +6360,23 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in) /* Return nonzero if anything in X contains a MEM. Look also for pseudo registers. */ -static int +int refers_to_mem_for_reload_p (rtx x) { const char *fmt; int i; - if (MEM_P (x)) + if (GET_CODE (x) == MEM) return 1; - if (REG_P (x)) + if (GET_CODE (x) == REG) return (REGNO (x) >= FIRST_PSEUDO_REGISTER && reg_equiv_memory_loc[REGNO (x)]); fmt = GET_RTX_FORMAT (GET_CODE (x)); for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) if (fmt[i] == 'e' - && (MEM_P (XEXP (x, i)) + && (GET_CODE (XEXP (x, i)) == MEM || refers_to_mem_for_reload_p (XEXP (x, i)))) return 1; @@ -6624,14 +6429,14 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, if (goal == 0) regno = goalreg; - else if (REG_P (goal)) + else if (GET_CODE (goal) == REG) regno = REGNO (goal); - else if (MEM_P (goal)) + else if (GET_CODE (goal) == MEM) { enum rtx_code code = GET_CODE (XEXP (goal, 0)); if (MEM_VOLATILE_P (goal)) return 0; - if (flag_float_store && SCALAR_FLOAT_MODE_P (GET_MODE (goal))) + if (flag_float_store && GET_MODE_CLASS (GET_MODE (goal)) == MODE_FLOAT) return 0; /* An address with side effects must be reexecuted. */ switch (code) @@ -6670,11 +6475,11 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, { p = PREV_INSN (p); num++; - if (p == 0 || LABEL_P (p) + if (p == 0 || GET_CODE (p) == CODE_LABEL || num > PARAM_VALUE (PARAM_MAX_RELOAD_SEARCH_INSNS)) return 0; - if (NONJUMP_INSN_P (p) + if (GET_CODE (p) == INSN /* If we don't want spill regs ... */ && (! (reload_reg_p != 0 && reload_reg_p != (short *) (HOST_WIDE_INT) 1) @@ -6683,7 +6488,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, different from what they were when calculating the need for spills. If we notice an input-reload insn here, we will reject it below, but it might hide a usable equivalent. - That makes bad code. It may even fail: perhaps no reg was + That makes bad code. It may even abort: perhaps no reg was spilled for this insn because it was assumed we would find that equivalent. */ || INSN_UID (p) < reload_first_uid)) @@ -6720,9 +6525,10 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, && ((rtx_equal_p (XEXP (tem, 0), goal) && (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0) - || (REG_P (SET_DEST (pat)) + || (GET_CODE (SET_DEST (pat)) == REG && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE - && SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (tem, 0))) + && (GET_MODE_CLASS (GET_MODE (XEXP (tem, 0))) + == MODE_FLOAT) && GET_CODE (goal) == CONST_INT && 0 != (goaltry = operand_subword (XEXP (tem, 0), 0, 0, @@ -6734,9 +6540,10 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, && (valueno = true_regnum (valtry)) >= 0))) || (goal_const && (tem = find_reg_note (p, REG_EQUIV, NULL_RTX)) - && REG_P (SET_DEST (pat)) + && GET_CODE (SET_DEST (pat)) == REG && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE - && SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (tem, 0))) + && (GET_MODE_CLASS (GET_MODE (XEXP (tem, 0))) + == MODE_FLOAT) && GET_CODE (goal) == CONST_INT && 0 != (goaltry = operand_subword (XEXP (tem, 0), 1, 0, VOIDmode)) @@ -6756,7 +6563,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, { int i; - for (i = hard_regno_nregs[valueno][mode] - 1; i >= 0; i--) + for (i = HARD_REGNO_NREGS (valueno, mode) - 1; i >= 0; i--) if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], valueno + i)) break; @@ -6798,22 +6605,20 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, if (goal_mem && value == SET_DEST (single_set (where)) && refers_to_regno_for_reload_p (valueno, (valueno - + hard_regno_nregs[valueno][mode]), + + HARD_REGNO_NREGS (valueno, mode)), goal, (rtx*) 0)) return 0; /* Reject registers that overlap GOAL. */ - if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER) - nregs = hard_regno_nregs[regno][mode]; - else - nregs = 1; - valuenregs = hard_regno_nregs[valueno][mode]; - if (!goal_mem && !goal_const - && regno + nregs > valueno && regno < valueno + valuenregs) + && regno + (int) HARD_REGNO_NREGS (regno, mode) > valueno + && regno < valueno + (int) HARD_REGNO_NREGS (valueno, mode)) return 0; + nregs = HARD_REGNO_NREGS (regno, mode); + valuenregs = HARD_REGNO_NREGS (valueno, mode); + /* Reject VALUE if it is one of the regs reserved for reloads. Reload1 knows how to reuse them anyway, and it would get confused if we allocated one without its knowledge. @@ -6838,8 +6643,8 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, if (rld[i].reg_rtx != 0 && rld[i].in) { int regno1 = REGNO (rld[i].reg_rtx); - int nregs1 = hard_regno_nregs[regno1] - [GET_MODE (rld[i].reg_rtx)]; + int nregs1 = HARD_REGNO_NREGS (regno1, + GET_MODE (rld[i].reg_rtx)); if (regno1 < valueno + valuenregs && regno1 + nregs1 > valueno) return 0; @@ -6863,7 +6668,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, /* Don't trust the conversion past a function call if either of the two is in a call-clobbered register, or memory. */ - if (CALL_P (p)) + if (GET_CODE (p) == CALL_INSN) { int i; @@ -6872,15 +6677,17 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER) for (i = 0; i < nregs; ++i) - if (call_used_regs[regno + i] - || HARD_REGNO_CALL_PART_CLOBBERED (regno + i, mode)) + if (call_used_regs[regno + i]) return 0; if (valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER) for (i = 0; i < valuenregs; ++i) - if (call_used_regs[valueno + i] - || HARD_REGNO_CALL_PART_CLOBBERED (valueno + i, mode)) + if (call_used_regs[valueno + i]) return 0; +#ifdef NON_SAVING_SETJMP + if (NON_SAVING_SETJMP && find_reg_note (p, REG_SETJMP, NULL)) + return 0; +#endif } if (INSN_P (p)) @@ -6903,14 +6710,15 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, rtx dest = SET_DEST (pat); while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == ZERO_EXTRACT + || GET_CODE (dest) == SIGN_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART) dest = XEXP (dest, 0); - if (REG_P (dest)) + if (GET_CODE (dest) == REG) { int xregno = REGNO (dest); int xnregs; if (REGNO (dest) < FIRST_PSEUDO_REGISTER) - xnregs = hard_regno_nregs[xregno][GET_MODE (dest)]; + xnregs = HARD_REGNO_NREGS (xregno, GET_MODE (dest)); else xnregs = 1; if (xregno < regno + nregs && xregno + xnregs > regno) @@ -6924,10 +6732,10 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, if (xregno == STACK_POINTER_REGNUM && need_stable_sp) return 0; } - else if (goal_mem && MEM_P (dest) + else if (goal_mem && GET_CODE (dest) == MEM && ! push_operand (dest, GET_MODE (dest))) return 0; - else if (MEM_P (dest) && regno >= FIRST_PSEUDO_REGISTER + else if (GET_CODE (dest) == MEM && regno >= FIRST_PSEUDO_REGISTER && reg_equiv_memory_loc[regno] != 0) return 0; else if (need_stable_sp && push_operand (dest, GET_MODE (dest))) @@ -6946,14 +6754,15 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, rtx dest = SET_DEST (v1); while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == ZERO_EXTRACT + || GET_CODE (dest) == SIGN_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART) dest = XEXP (dest, 0); - if (REG_P (dest)) + if (GET_CODE (dest) == REG) { int xregno = REGNO (dest); int xnregs; if (REGNO (dest) < FIRST_PSEUDO_REGISTER) - xnregs = hard_regno_nregs[xregno][GET_MODE (dest)]; + xnregs = HARD_REGNO_NREGS (xregno, GET_MODE (dest)); else xnregs = 1; if (xregno < regno + nregs @@ -6969,10 +6778,10 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, if (xregno == STACK_POINTER_REGNUM && need_stable_sp) return 0; } - else if (goal_mem && MEM_P (dest) + else if (goal_mem && GET_CODE (dest) == MEM && ! push_operand (dest, GET_MODE (dest))) return 0; - else if (MEM_P (dest) && regno >= FIRST_PSEUDO_REGISTER + else if (GET_CODE (dest) == MEM && regno >= FIRST_PSEUDO_REGISTER && reg_equiv_memory_loc[regno] != 0) return 0; else if (need_stable_sp @@ -6982,7 +6791,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, } } - if (CALL_P (p) && CALL_INSN_FUNCTION_USAGE (p)) + if (GET_CODE (p) == CALL_INSN && CALL_INSN_FUNCTION_USAGE (p)) { rtx link; @@ -6994,11 +6803,11 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, { rtx dest = SET_DEST (pat); - if (REG_P (dest)) + if (GET_CODE (dest) == REG) { int xregno = REGNO (dest); int xnregs - = hard_regno_nregs[xregno][GET_MODE (dest)]; + = HARD_REGNO_NREGS (xregno, GET_MODE (dest)); if (xregno < regno + nregs && xregno + xnregs > regno) @@ -7012,7 +6821,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, return 0; } - else if (goal_mem && MEM_P (dest) + else if (goal_mem && GET_CODE (dest) == MEM && ! push_operand (dest, GET_MODE (dest))) return 0; else if (need_stable_sp @@ -7032,7 +6841,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other, for (link = REG_NOTES (p); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == REG_INC - && REG_P (XEXP (link, 0))) + && GET_CODE (XEXP (link, 0)) == REG) { int incno = REGNO (XEXP (link, 0)); if (incno < regno + nregs && incno >= regno) @@ -7106,64 +6915,25 @@ find_inc_amount (rtx x, rtx inced) return 0; } -/* Return 1 if registers from REGNO to ENDREGNO are the subjects of a - REG_INC note in insn INSN. REGNO must refer to a hard register. */ - -#ifdef AUTO_INC_DEC -static int -reg_inc_found_and_valid_p (unsigned int regno, unsigned int endregno, - rtx insn) -{ - rtx link; - - gcc_assert (insn); - - if (! INSN_P (insn)) - return 0; - - for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) - if (REG_NOTE_KIND (link) == REG_INC) - { - unsigned int test = (int) REGNO (XEXP (link, 0)); - if (test >= regno && test < endregno) - return 1; - } - return 0; -} -#else - -#define reg_inc_found_and_valid_p(regno,endregno,insn) 0 - -#endif - /* Return 1 if register REGNO is the subject of a clobber in insn INSN. - If SETS is 1, also consider SETs. If SETS is 2, enable checking - REG_INC. REGNO must refer to a hard register. */ + If SETS is nonzero, also consider SETs. */ int regno_clobbered_p (unsigned int regno, rtx insn, enum machine_mode mode, int sets) { - unsigned int nregs, endregno; - - /* regno must be a hard register. */ - gcc_assert (regno < FIRST_PSEUDO_REGISTER); - - nregs = hard_regno_nregs[regno][mode]; - endregno = regno + nregs; + unsigned int nregs = HARD_REGNO_NREGS (regno, mode); + unsigned int endregno = regno + nregs; if ((GET_CODE (PATTERN (insn)) == CLOBBER - || (sets == 1 && GET_CODE (PATTERN (insn)) == SET)) - && REG_P (XEXP (PATTERN (insn), 0))) + || (sets && GET_CODE (PATTERN (insn)) == SET)) + && GET_CODE (XEXP (PATTERN (insn), 0)) == REG) { unsigned int test = REGNO (XEXP (PATTERN (insn), 0)); return test >= regno && test < endregno; } - if (sets == 2 && reg_inc_found_and_valid_p (regno, endregno, insn)) - return 1; - if (GET_CODE (PATTERN (insn)) == PARALLEL) { int i = XVECLEN (PATTERN (insn), 0) - 1; @@ -7172,17 +6942,14 @@ regno_clobbered_p (unsigned int regno, rtx insn, enum machine_mode mode, { rtx elt = XVECEXP (PATTERN (insn), 0, i); if ((GET_CODE (elt) == CLOBBER - || (sets == 1 && GET_CODE (PATTERN (insn)) == SET)) - && REG_P (XEXP (elt, 0))) + || (sets && GET_CODE (PATTERN (insn)) == SET)) + && GET_CODE (XEXP (elt, 0)) == REG) { unsigned int test = REGNO (XEXP (elt, 0)); if (test >= regno && test < endregno) return 1; } - if (sets == 2 - && reg_inc_found_and_valid_p (regno, endregno, elt)) - return 1; } } @@ -7201,8 +6968,8 @@ reload_adjust_reg_for_mode (rtx reloadreg, enum machine_mode mode) regno = REGNO (reloadreg); if (WORDS_BIG_ENDIAN) - regno += (int) hard_regno_nregs[regno][GET_MODE (reloadreg)] - - (int) hard_regno_nregs[regno][mode]; + regno += HARD_REGNO_NREGS (regno, GET_MODE (reloadreg)) + - HARD_REGNO_NREGS (regno, mode); return gen_rtx_REG (mode, regno); } @@ -7222,6 +6989,8 @@ static const char *const reload_when_needed_name[] = "RELOAD_FOR_OTHER_ADDRESS" }; +static const char * const reg_class_names[] = REG_CLASS_NAMES; + /* These functions are used to print the variables set by 'find_reloads' */ void diff --git a/contrib/gcc/toplev.c b/contrib/gcc/toplev.c index 53fcdfe..da20354 100644 --- a/contrib/gcc/toplev.c +++ b/contrib/gcc/toplev.c @@ -1,7 +1,6 @@ /* Top level of GCC compilers (cc1, cc1plus, etc.) Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -17,8 +16,10 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* $FreeBSD$ */ /* This is the top level of cc1/c++. It parses command args, opens files, invokes the various passes @@ -41,10 +42,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA # include <sys/times.h> #endif -#include "line-map.h" #include "input.h" #include "tree.h" -#include "version.h" #include "rtl.h" #include "tm_p.h" #include "flags.h" @@ -62,6 +61,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "intl.h" #include "ggc.h" #include "graph.h" +#include "loop.h" #include "regs.h" #include "timevar.h" #include "diagnostic.h" @@ -81,7 +81,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "coverage.h" #include "value-prof.h" #include "alloc-pool.h" -#include "tree-mudflap.h" #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) #include "dwarf2out.h" @@ -100,6 +99,18 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA declarations for e.g. AIX 4.x. */ #endif +#ifndef HAVE_conditional_execution +#define HAVE_conditional_execution 0 +#endif + +/* Carry information from ASM_DECLARE_OBJECT_NAME + to ASM_FINISH_DECLARE_OBJECT. */ + +extern int size_directive_output; +extern tree last_assemble_variable_decl; + +extern void reg_alloc (void); + static void general_init (const char *); static void do_compile (void); static void process_options (void); @@ -118,6 +129,43 @@ static int print_single_switch (FILE *, int, int, const char *, static void print_switch_values (FILE *, int, int, const char *, const char *, const char *); +/* Rest of compilation helper functions. */ +static bool rest_of_handle_inlining (tree); +static void rest_of_handle_cse (tree, rtx); +static void rest_of_handle_cse2 (tree, rtx); +static void rest_of_handle_gcse (tree, rtx); +static void rest_of_handle_life (tree, rtx); +static void rest_of_handle_loop_optimize (tree, rtx); +static void rest_of_handle_loop2 (tree, rtx); +static void rest_of_handle_jump_bypass (tree, rtx); +static void rest_of_handle_sibling_calls (rtx); +static void rest_of_handle_null_pointer (tree, rtx); +static void rest_of_handle_addressof (tree, rtx); +static void rest_of_handle_cfg (tree, rtx); +static void rest_of_handle_branch_prob (tree, rtx); +static void rest_of_handle_value_profile_transformations (tree, rtx); +static void rest_of_handle_if_conversion (tree, rtx); +static void rest_of_handle_if_after_combine (tree, rtx); +static void rest_of_handle_tracer (tree, rtx); +static void rest_of_handle_combine (tree, rtx); +static void rest_of_handle_regmove (tree, rtx); +#ifdef INSN_SCHEDULING +static void rest_of_handle_sched (tree, rtx); +static void rest_of_handle_sched2 (tree, rtx); +#endif +static bool rest_of_handle_new_regalloc (tree, rtx); +static bool rest_of_handle_old_regalloc (tree, rtx); +static void rest_of_handle_regrename (tree, rtx); +static void rest_of_handle_reorder_blocks (tree, rtx); +#ifdef STACK_REGS +static void rest_of_handle_stack_regs (tree, rtx); +#endif +static void rest_of_handle_machine_reorg (tree, rtx); +#ifdef DELAY_SLOTS +static void rest_of_handle_delay_slots (tree, rtx); +#endif +static void rest_of_handle_final (tree, rtx); + /* Nonzero to dump debug info whilst parsing (-dy option). */ static int set_yydebug; @@ -140,20 +188,10 @@ static const char **save_argv; const char *main_input_filename; -#ifndef USE_MAPPED_LOCATION -location_t unknown_location = { NULL, 0 }; -#endif - -/* Used to enable -fvar-tracking, -fweb and -frename-registers according - to optimize and default_debug_hooks in process_options (). */ -#define AUTODETECT_VALUE 2 - /* Current position in real source file. */ location_t input_location; -struct line_maps line_table; - /* Nonzero if it is unsafe to create any new pseudo registers. */ int no_new_pseudos; @@ -164,16 +202,6 @@ struct file_stack *input_file_stack; /* Incremented on each change to input_file_stack. */ int input_file_stack_tick; -/* Record of input_file_stack at each tick. */ -typedef struct file_stack *fs_p; -DEF_VEC_P(fs_p); -DEF_VEC_ALLOC_P(fs_p,heap); -static VEC(fs_p,heap) *input_file_stack_history; - -/* Whether input_file_stack has been restored to a previous state (in - which case there should be no more pushing). */ -static bool input_file_stack_restored; - /* Name to use as base of names for dump output files. */ const char *dump_base_name; @@ -182,6 +210,11 @@ const char *dump_base_name; const char *aux_base_name; +/* Format to use to print dumpfile index value */ +#ifndef DUMPFILE_FORMAT +#define DUMPFILE_FORMAT ".%02d." +#endif + /* Bit flags that specify the machine subtype we are compiling for. Bits are tested using macros TARGET_... defined in the tm.h file and set by `-m...' switches. Must be defined in rtlanal.c. */ @@ -197,9 +230,123 @@ int target_flags_explicit; const struct gcc_debug_hooks *debug_hooks; -/* Debug hooks - target default. */ +/* Describes a dump file. */ -static const struct gcc_debug_hooks *default_debug_hooks; +struct dump_file_info +{ + /* The unique extension to apply, e.g. ".jump". */ + const char *const extension; + + /* The -d<c> character that enables this dump file. */ + char const debug_switch; + + /* True if there is a corresponding graph dump file. */ + char const graph_dump_p; + + /* True if the user selected this dump. */ + char enabled; + + /* True if the files have been initialized (ie truncated). */ + char initialized; +}; + +/* Enumerate the extant dump files. */ + +enum dump_file_index +{ + DFI_cgraph, + DFI_rtl, + DFI_sibling, + DFI_eh, + DFI_jump, + DFI_null, + DFI_cse, + DFI_addressof, + DFI_gcse, + DFI_loop, + DFI_bypass, + DFI_cfg, + DFI_bp, + DFI_vpt, + DFI_ce1, + DFI_tracer, + DFI_loop2, + DFI_web, + DFI_cse2, + DFI_life, + DFI_combine, + DFI_ce2, + DFI_regmove, + DFI_sched, + DFI_lreg, + DFI_greg, + DFI_postreload, + DFI_flow2, + DFI_peephole2, + DFI_ce3, + DFI_rnreg, + DFI_bbro, + DFI_branch_target_load, + DFI_sched2, + DFI_stack, + DFI_mach, + DFI_dbr, + DFI_MAX +}; + +/* Describes all the dump files. Should be kept in order of the + pass and in sync with dump_file_index above. + + Remaining -d letters: + + " e m q " + " JK O Q WXY " +*/ + +static struct dump_file_info dump_file[DFI_MAX] = +{ + { "cgraph", 'U', 0, 0, 0 }, + { "rtl", 'r', 0, 0, 0 }, + { "sibling", 'i', 0, 0, 0 }, + { "eh", 'h', 0, 0, 0 }, + { "jump", 'j', 0, 0, 0 }, + { "null", 'u', 0, 0, 0 }, + { "cse", 's', 0, 0, 0 }, + { "addressof", 'F', 0, 0, 0 }, + { "gcse", 'G', 1, 0, 0 }, + { "loop", 'L', 1, 0, 0 }, + { "bypass", 'G', 1, 0, 0 }, /* Yes, duplicate enable switch. */ + { "cfg", 'f', 1, 0, 0 }, + { "bp", 'b', 1, 0, 0 }, + { "vpt", 'V', 1, 0, 0 }, + { "ce1", 'C', 1, 0, 0 }, + { "tracer", 'T', 1, 0, 0 }, + { "loop2", 'L', 1, 0, 0 }, + { "web", 'Z', 0, 0, 0 }, + { "cse2", 't', 1, 0, 0 }, + { "life", 'f', 1, 0, 0 }, /* Yes, duplicate enable switch. */ + { "combine", 'c', 1, 0, 0 }, + { "ce2", 'C', 1, 0, 0 }, + { "regmove", 'N', 1, 0, 0 }, + { "sched", 'S', 1, 0, 0 }, + { "lreg", 'l', 1, 0, 0 }, + { "greg", 'g', 1, 0, 0 }, + { "postreload", 'o', 1, 0, 0 }, + { "flow2", 'w', 1, 0, 0 }, + { "peephole2", 'z', 1, 0, 0 }, + { "ce3", 'E', 1, 0, 0 }, + { "rnreg", 'n', 1, 0, 0 }, + { "bbro", 'B', 1, 0, 0 }, + { "btl", 'd', 1, 0, 0 }, /* Yes, duplicate enable switch. */ + { "sched2", 'R', 1, 0, 0 }, + { "stack", 'k', 1, 0, 0 }, + { "mach", 'M', 1, 0, 0 }, + { "dbr", 'd', 0, 0, 0 }, +}; + +static int open_dump_file (enum dump_file_index, tree); +static void close_dump_file (enum dump_file_index, + void (*) (FILE *, rtx), rtx); /* Other flags saying which kinds of debugging dump have been requested. */ @@ -231,15 +378,80 @@ int optimize_size = 0; or 0 if between functions. */ tree current_function_decl; -/* Set to the FUNC_BEGIN label of the current function, or NULL +/* Set to the FUNC_BEGIN label of the current function, or NULL_TREE if none. */ -const char * current_function_func_begin_label; +tree current_function_func_begin_label; + +/* Nonzero if doing dwarf2 duplicate elimination. */ + +int flag_eliminate_dwarf2_dups = 0; + +/* Nonzero if doing unused type elimination. */ + +int flag_eliminate_unused_debug_types = 1; + +/* Nonzero means emit debugging information only for symbols which are used. */ +int flag_debug_only_used_symbols = 0; + +/* Nonzero if generating code to do profiling. */ + +int profile_flag = 0; + +/* Nonzero if generating code to profile program flow graph arcs. */ + +int profile_arc_flag = 0; + +/* Nonzero if value histograms should be measured. */ + +int flag_profile_values = 0; + +/* Nonzero if value histograms should be used to optimize code. */ +int flag_value_profile_transformations = 0; + +/* Nonzero if generating info for gcov to calculate line test coverage. */ + +int flag_test_coverage = 0; + +/* Nonzero indicates that branch taken probabilities should be calculated. */ + +int flag_branch_probabilities = 0; + +/* Nonzero if basic blocks should be reordered. */ + +int flag_reorder_blocks = 0; + +/* Nonzero if functions should be reordered. */ + +int flag_reorder_functions = 0; + +/* Nonzero if registers should be renamed. */ + +int flag_rename_registers = 0; +int flag_cprop_registers = 0; + +/* Nonzero for -pedantic switch: warn about anything + that standard spec forbids. */ + +int pedantic = 0; /* Temporarily suppress certain warnings. This is set while reading code from a system header file. */ int in_system_header = 0; +/* Don't print functions as they are compiled. -quiet. */ + +int quiet_flag = 0; + +/* Print times taken by the various passes. -ftime-report. */ + +int time_report = 0; + +/* Print memory still in use at end of compilation (which may have little + to do with peak memory consumption). -fmem-report. */ + +int mem_report = 0; + /* Nonzero means to collect statistics which might be expensive and to print them when we are done. */ int flag_detailed_statistics = 0; @@ -258,11 +470,16 @@ unsigned local_tick; int flag_signed_char; -/* Nonzero means give an enum type only as many bytes as it needs. A value - of 2 means it has not yet been initialized. */ +/* Nonzero means give an enum type only as many bytes as it needs. */ int flag_short_enums; +/* Nonzero for -fcaller-saves: allocate values in regs that need to + be saved across function calls, if that produces overall better code. + Optional now, so people can test it. */ + +int flag_caller_saves = 0; + /* Nonzero if structures and unions should be returned in memory. This should only be defined if compatibility with another compiler or @@ -276,17 +493,259 @@ int flag_short_enums; int flag_pcc_struct_return = DEFAULT_PCC_STRUCT_RETURN; +/* Nonzero for -fforce-mem: load memory value into a register + before arithmetic on it. This makes better cse but slower compilation. */ + +int flag_force_mem = 0; + +/* Nonzero for -fforce-addr: load memory address into a register before + reference to memory. This makes better cse but slower compilation. */ + +int flag_force_addr = 0; + +/* Nonzero for -fdefer-pop: don't pop args after each function call; + instead save them up to pop many calls' args with one insns. */ + +int flag_defer_pop = 0; + +/* Nonzero for -ffloat-store: don't allocate floats and doubles + in extended-precision registers. */ + +int flag_float_store = 0; + +/* Nonzero for -fcse-follow-jumps: + have cse follow jumps to do a more extensive job. */ + +int flag_cse_follow_jumps; + +/* Nonzero for -fcse-skip-blocks: + have cse follow a branch around a block. */ +int flag_cse_skip_blocks; + +/* Nonzero for -fexpensive-optimizations: + perform miscellaneous relatively-expensive optimizations. */ +int flag_expensive_optimizations; + +/* Nonzero for -fthread-jumps: + have jump optimize output of loop. */ + +int flag_thread_jumps; + +/* Nonzero enables strength-reduction in loop.c. */ + +int flag_strength_reduce = 0; + +/* Nonzero enables loop unrolling in unroll.c. Only loops for which the + number of iterations can be calculated at compile-time (UNROLL_COMPLETELY, + UNROLL_MODULO) or at run-time (preconditioned to be UNROLL_MODULO) are + unrolled. */ + +int flag_old_unroll_loops; + +/* Nonzero enables loop unrolling in unroll.c. All loops are unrolled. + This is generally not a win. */ + +int flag_old_unroll_all_loops; + +/* Enables unrolling of simple loops in loop-unroll.c. */ +int flag_unroll_loops; + +/* Enables unrolling of all loops in loop-unroll.c. */ +int flag_unroll_all_loops; + +/* Nonzero enables loop peeling. */ +int flag_peel_loops; + +/* Nonzero enables loop unswitching. */ +int flag_unswitch_loops; + +/* Nonzero enables prefetch optimizations for arrays in loops. */ + +int flag_prefetch_loop_arrays; + +/* Nonzero forces all invariant computations in loops to be moved + outside the loop. */ + +int flag_move_all_movables = 0; + +/* Nonzero forces all general induction variables in loops to be + strength reduced. */ + +int flag_reduce_all_givs = 0; + +/* Nonzero to perform full register move optimization passes. This is the + default for -O2. */ + +int flag_regmove = 0; + +/* Nonzero for -fwritable-strings: + store string constants in data segment and don't uniquize them. */ + +int flag_writable_strings = 0; + +/* Nonzero means don't put addresses of constant functions in registers. + Used for compiling the Unix kernel, where strange substitutions are + done on the assembly output. */ + +int flag_no_function_cse = 0; + +/* Nonzero for -fomit-frame-pointer: + don't make a frame pointer in simple functions that don't require one. */ + +int flag_omit_frame_pointer = 0; + +/* Nonzero means place each function into its own section on those platforms + which support arbitrary section names and unlimited numbers of sections. */ + +int flag_function_sections = 0; + +/* ... and similar for data. */ + +int flag_data_sections = 0; + +/* Nonzero to inhibit use of define_optimization peephole opts. */ + +int flag_no_peephole = 0; + +/* Nonzero allows GCC to optimize sibling and tail recursive calls. */ + +int flag_optimize_sibling_calls = 0; + +/* Nonzero means the front end generally wants `errno' maintained by math + operations, like built-in SQRT. */ + +int flag_errno_math = 1; + +/* Nonzero means that unsafe floating-point math optimizations are allowed + for the sake of speed. IEEE compliance is not guaranteed, and operations + are allowed to assume that their arguments and results are "normal" + (e.g., nonnegative for SQRT). */ + +int flag_unsafe_math_optimizations = 0; + +/* Nonzero means that no NaNs or +-Infs are expected. */ + +int flag_finite_math_only = 0; + +/* Zero means that floating-point math operations cannot generate a + (user-visible) trap. This is the case, for example, in nonstop + IEEE 754 arithmetic. Trapping conditions include division by zero, + overflow, underflow, invalid and inexact, but does not include + operations on signaling NaNs (see below). */ + +int flag_trapping_math = 1; + +/* Nonzero means disable transformations that assume default floating + point rounding behavior. */ + +int flag_rounding_math = 0; + +/* Nonzero means disable transformations observable by signaling NaNs. + This option implies that any operation on an IEEE signaling NaN can + generate a (user-visible) trap. */ + +int flag_signaling_nans = 0; + /* 0 means straightforward implementation of complex divide acceptable. 1 means wide ranges of inputs must work for complex divide. - 2 means C99-like requirements for complex multiply and divide. */ + 2 means C99-like requirements for complex divide (not yet implemented). */ + +int flag_complex_divide_method = 0; + +/* Nonzero means just do syntax checking; don't output anything. */ + +int flag_syntax_only = 0; + +/* Nonzero means performs web construction pass. */ + +int flag_web; + +/* Nonzero means perform loop optimizer. */ + +int flag_loop_optimize; + +/* Nonzero means perform crossjumping. */ + +int flag_crossjumping; + +/* Nonzero means perform if conversion. */ + +int flag_if_conversion; + +/* Nonzero means perform if conversion after reload. */ + +int flag_if_conversion2; + +/* Nonzero means to use global dataflow analysis to eliminate + useless null pointer tests. */ + +int flag_delete_null_pointer_checks; + +/* Nonzero means perform global CSE. */ -int flag_complex_method = 1; +int flag_gcse = 0; + +/* Nonzero means to do the enhanced load motion during gcse, which trys + to hoist loads by not killing them when a store to the same location + is seen. */ + +int flag_gcse_lm = 1; + +/* Nonzero means to perform store motion after gcse, which will try to + move stores closer to the exit block. Its not very effective without + flag_gcse_lm. */ + +int flag_gcse_sm = 1; + +/* Nonzero if we want to perfrom redundant load after store elimination + in gcse. */ + +int flag_gcse_las = 1; + +/* Perform target register optimization before prologue / epilogue + threading. */ + +int flag_branch_target_load_optimize = 0; + +/* Perform target register optimization after prologue / epilogue + threading and jump2. */ + +int flag_branch_target_load_optimize2 = 0; + +/* Nonzero means to rerun cse after loop optimization. This increases + compilation time about 20% and picks up a few more common expressions. */ + +int flag_rerun_cse_after_loop; + +/* Nonzero means to run loop optimizations twice. */ + +int flag_rerun_loop_opt; + +/* Nonzero for -finline-functions: ok to inline functions that look like + good inline candidates. */ + +int flag_inline_functions; + +/* Nonzero for -fkeep-inline-functions: even if we make a function + go inline everywhere, keep its definition around for debugging + purposes. */ + +int flag_keep_inline_functions; + +/* Nonzero means that functions will not be inlined. */ + +int flag_no_inline = 2; /* Nonzero means that we don't want inlining by virtue of -fno-inline, not just because the tree inliner turned us off. */ int flag_really_no_inline = 2; +/* Nonzero means that we should emit static const variables + regardless of whether or not optimization is turned on. */ + +int flag_keep_static_consts = 1; + /* Nonzero means we should be saving declaration info into a .X file. */ int flag_gen_aux_info = 0; @@ -295,28 +754,124 @@ int flag_gen_aux_info = 0; const char *aux_info_file_name; +/* Nonzero means make the text shared if supported. */ + +int flag_shared_data; + +/* Nonzero means schedule into delayed branch slots if supported. */ + +int flag_delayed_branch; + +/* Nonzero if we are compiling pure (sharable) code. + Value is 1 if we are doing "small" pic; value is 2 if we're doing + "large" pic. */ + +int flag_pic; + +/* Nonzero if we are compiling position independent code for executable. + The value is 1 if we are doing "small" pic; value is 2 if we're doing + "large" pic. */ + +int flag_pie; + /* Nonzero if we are compiling code for a shared library, zero for executable. */ int flag_shlib; -/* Generate code for GNU or NeXT Objective-C runtime environment. */ - -#ifdef NEXT_OBJC_RUNTIME -int flag_next_runtime = 1; -#else -int flag_next_runtime = 0; -#endif - /* Set to the default thread-local storage (tls) model to use. */ enum tls_model flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC; +/* Nonzero means generate extra code for exception handling and enable + exception handling. */ + +int flag_exceptions; + +/* Nonzero means generate frame unwind info table when supported. */ + +int flag_unwind_tables = 0; + +/* Nonzero means generate frame unwind info table exact at each insn + boundary. */ + +int flag_asynchronous_unwind_tables = 0; + +/* Nonzero means don't place uninitialized global data in common storage + by default. */ + +int flag_no_common; + /* Nonzero means change certain warnings into errors. Usually these are warnings about failure to conform to some standard. */ int flag_pedantic_errors = 0; +/* flag_schedule_insns means schedule insns within basic blocks (before + local_alloc). + flag_schedule_insns_after_reload means schedule insns after + global_alloc. */ + +int flag_schedule_insns = 0; +int flag_schedule_insns_after_reload = 0; + +/* When flag_schedule_insns_after_reload is set, use EBB scheduler. */ +int flag_sched2_use_superblocks = 0; + +/* When flag_schedule_insns_after_reload is set, construct traces and EBB + scheduler. */ +int flag_sched2_use_traces = 0; + +/* The following flags have effect only for scheduling before register + allocation: + + flag_schedule_interblock means schedule insns across basic blocks. + flag_schedule_speculative means allow speculative motion of non-load insns. + flag_schedule_speculative_load means allow speculative motion of some + load insns. + flag_schedule_speculative_load_dangerous allows speculative motion of more + load insns. */ + +int flag_schedule_interblock = 1; +int flag_schedule_speculative = 1; +int flag_schedule_speculative_load = 0; +int flag_schedule_speculative_load_dangerous = 0; + +/* The following flags have an effect during scheduling after register + allocation: + + flag_sched_stalled_insns means that insns can be moved prematurely from the queue + of stalled insns into the ready list. + + flag_sched_stalled_insns_dep controls how many insn groups will be examined + for a dependency on a stalled insn that is candidate for premature removal + from the queue of stalled insns into the ready list (has an effect only if + the flag 'sched_stalled_insns' is set). */ + +int flag_sched_stalled_insns = 0; +int flag_sched_stalled_insns_dep = 1; + +int flag_single_precision_constant; + +/* flag_branch_on_count_reg means try to replace add-1,compare,branch tupple + by a cheaper branch on a count register. */ +int flag_branch_on_count_reg = 1; + +/* -finhibit-size-directive inhibits output of .size for ELF. + This is used only for compiling crtstuff.c, + and it may be extended to other effects + needed for crtstuff.c on other systems. */ +int flag_inhibit_size_directive = 0; + +/* -fverbose-asm causes extra commentary information to be produced in + the generated assembly code (to make it more readable). This option + is generally only of use to those who actually need to read the + generated assembly code (perhaps while debugging the compiler itself). + -fno-verbose-asm, the default, causes the extra information + to be omitted and is useful when comparing two assembler files. */ + +int flag_verbose_asm = 0; + /* -dA causes debug commentary information to be produced in the generated assembly code (to make it more readable). This option is generally only of use to those who actually need to read the @@ -330,6 +885,19 @@ int flag_debug_asm = 0; int flag_dump_rtl_in_asm = 0; +/* Nonzero means put zero initialized data in the bss section. */ +int flag_zero_initialized_in_bss = 1; + +/* Tag all structures with __attribute__(packed). */ +int flag_pack_struct = 0; + +/* Nonzero means that -Wformat accepts certain system-dependent formats. */ +int flag_format_extensions = 0; + +/* Emit code to check for stack overflow; also may cause large objects + to be allocated dynamically. */ +int flag_stack_check; + /* When non-NULL, indicates that whenever space is allocated on the stack, the resulting stack pointer must not pass this address---that is, for stacks that grow downward, the stack pointer @@ -339,32 +907,77 @@ int flag_dump_rtl_in_asm = 0; the support provided depends on the backend. */ rtx stack_limit_rtx; +/* 0 if pointer arguments may alias each other. True in C. + 1 if pointer arguments may not alias each other but may alias + global variables. + 2 if pointer arguments may not alias each other and may not + alias global variables. True in Fortran. + This defaults to 0 for C. */ +int flag_argument_noalias = 0; + +/* Nonzero if we should do (language-dependent) alias analysis. + Typically, this analysis will assume that expressions of certain + types do not alias expressions of certain other types. Only used + if alias analysis (in general) is enabled. */ +int flag_strict_aliasing = 0; + +/* Instrument functions with calls at entry and exit, for profiling. */ +int flag_instrument_function_entry_exit = 0; + +/* Nonzero means ignore `#ident' directives. 0 means handle them. + On SVR4 targets, it also controls whether or not to emit a + string identifying the compiler. */ + +int flag_no_ident = 0; + +/* This will perform a peephole pass before sched2. */ +int flag_peephole2 = 0; + +/* This will try to guess branch probabilities. */ +int flag_guess_branch_prob = 0; + +/* -fcheck-bounds causes gcc to generate array bounds checks. + For C, C++, ObjC: defaults to off. + For Java: defaults to on. + For Fortran: defaults to off. */ +int flag_bounds_check = 0; + +/* This will attempt to merge constant section constants, if 1 only + string constants and constants from constant pool, if 2 also constant + variables. */ +int flag_merge_constants = 1; + /* If one, renumber instruction UIDs to reduce the number of unused UIDs if there are a lot of instructions. If greater than one, unconditionally renumber instruction UIDs. */ int flag_renumber_insns = 1; -/* Nonzero if we should track variables. When - flag_var_tracking == AUTODETECT_VALUE it will be set according - to optimize, debug_info_level and debug_hooks in process_options (). */ -int flag_var_tracking = AUTODETECT_VALUE; +/* If nonzero, use the graph coloring register allocator. */ +int flag_new_regalloc = 0; + +/* Nonzero if we perform superblock formation. */ -/* True if the user has tagged the function with the 'section' - attribute. */ +int flag_tracer = 0; -bool user_defined_section_attribute = false; +/* Nonzero if we perform whole unit at a time compilation. */ + +int flag_unit_at_a_time = 0; /* Values of the -falign-* flags: how much to align labels in code. 0 means `use default', 1 means `don't align'. For each variable, there is an _log variant which is the power of two not less than the variable, for .align output. */ +int align_loops; int align_loops_log; int align_loops_max_skip; +int align_jumps; int align_jumps_log; int align_jumps_max_skip; +int align_labels; int align_labels_log; int align_labels_max_skip; +int align_functions; int align_functions_log; /* Like align_functions_log above, but used by front-ends to force the @@ -379,27 +992,216 @@ typedef struct } lang_independent_options; +/* Nonzero if signed arithmetic overflow should trap. */ +int flag_trapv = 0; + +/* Nonzero if signed arithmetic overflow should wrap around. */ +int flag_wrapv = 0; + /* Nonzero if subexpressions must be evaluated from left-to-right. */ int flag_evaluation_order = 0; +/* Add or remove a leading underscore from user symbols. */ +int flag_leading_underscore = -1; + +/* The version of the C++ ABI in use. The following values are + allowed: + + 0: The version of the ABI believed most conformant with the + C++ ABI specification. This ABI may change as bugs are + discovered and fixed. Therefore, 0 will not necessarily + indicate the same ABI in different versions of G++. + + 1: The version of the ABI first used in G++ 3.2. + + 2: The version of the ABI first used in G++ 3.4. + + Additional positive integers will be assigned as new versions of + the ABI become the default version of the ABI. */ + +int flag_abi_version = 2; + /* The user symbol prefix after having resolved same. */ const char *user_label_prefix; static const param_info lang_independent_params[] = { -#define DEFPARAM(ENUM, OPTION, HELP, DEFAULT, MIN, MAX) \ - { OPTION, DEFAULT, MIN, MAX, HELP }, +#define DEFPARAM(ENUM, OPTION, HELP, DEFAULT) \ + { OPTION, DEFAULT, HELP }, #include "params.def" #undef DEFPARAM - { NULL, 0, 0, 0, NULL } + { NULL, 0, NULL } }; +/* Table of language-independent -f options. + STRING is the option name. VARIABLE is the address of the variable. + ON_VALUE is the value to store in VARIABLE + if `-fSTRING' is seen as an option. + (If `-fno-STRING' is seen as an option, the opposite value is stored.) */ + +static const lang_independent_options f_options[] = +{ + {"format-extensions", &flag_format_extensions, 1}, + {"eliminate-dwarf2-dups", &flag_eliminate_dwarf2_dups, 1 }, + {"eliminate-unused-debug-symbols", &flag_debug_only_used_symbols, 1 }, + {"eliminate-unused-debug-types", &flag_eliminate_unused_debug_types, 1 }, + {"float-store", &flag_float_store, 1 }, + {"defer-pop", &flag_defer_pop, 1 }, + {"omit-frame-pointer", &flag_omit_frame_pointer, 1 }, + {"optimize-sibling-calls", &flag_optimize_sibling_calls, 1 }, + {"tracer", &flag_tracer, 1 }, + {"unit-at-a-time", &flag_unit_at_a_time, 1 }, + {"cse-follow-jumps", &flag_cse_follow_jumps, 1 }, + {"cse-skip-blocks", &flag_cse_skip_blocks, 1 }, + {"expensive-optimizations", &flag_expensive_optimizations, 1 }, + {"thread-jumps", &flag_thread_jumps, 1 }, + {"strength-reduce", &flag_strength_reduce, 1 }, + {"unroll-loops", &flag_unroll_loops, 1 }, + {"unroll-all-loops", &flag_unroll_all_loops, 1 }, + {"old-unroll-loops", &flag_old_unroll_loops, 1 }, + {"old-unroll-all-loops", &flag_old_unroll_all_loops, 1 }, + {"peel-loops", &flag_peel_loops, 1 }, + {"unswitch-loops", &flag_unswitch_loops, 1 }, + {"prefetch-loop-arrays", &flag_prefetch_loop_arrays, 1 }, + {"move-all-movables", &flag_move_all_movables, 1 }, + {"reduce-all-givs", &flag_reduce_all_givs, 1 }, + {"writable-strings", &flag_writable_strings, 1 }, + {"peephole", &flag_no_peephole, 0 }, + {"force-mem", &flag_force_mem, 1 }, + {"force-addr", &flag_force_addr, 1 }, + {"function-cse", &flag_no_function_cse, 0 }, + {"inline-functions", &flag_inline_functions, 1 }, + {"keep-inline-functions", &flag_keep_inline_functions, 1 }, + {"inline", &flag_no_inline, 0 }, + {"keep-static-consts", &flag_keep_static_consts, 1 }, + {"syntax-only", &flag_syntax_only, 1 }, + {"shared-data", &flag_shared_data, 1 }, + {"caller-saves", &flag_caller_saves, 1 }, + {"pcc-struct-return", &flag_pcc_struct_return, 1 }, + {"reg-struct-return", &flag_pcc_struct_return, 0 }, + {"delayed-branch", &flag_delayed_branch, 1 }, + {"web", &flag_web, 1}, + {"gcse", &flag_gcse, 1 }, + {"gcse-lm", &flag_gcse_lm, 1 }, + {"gcse-sm", &flag_gcse_sm, 1 }, + {"gcse-las", &flag_gcse_las, 1 }, + {"branch-target-load-optimize", &flag_branch_target_load_optimize, 1 }, + {"branch-target-load-optimize2", &flag_branch_target_load_optimize2, 1 }, + {"loop-optimize", &flag_loop_optimize, 1 }, + {"crossjumping", &flag_crossjumping, 1 }, + {"if-conversion", &flag_if_conversion, 1 }, + {"if-conversion2", &flag_if_conversion2, 1 }, + {"rerun-cse-after-loop", &flag_rerun_cse_after_loop, 1 }, + {"rerun-loop-opt", &flag_rerun_loop_opt, 1 }, + {"delete-null-pointer-checks", &flag_delete_null_pointer_checks, 1 }, + {"schedule-insns", &flag_schedule_insns, 1 }, + {"schedule-insns2", &flag_schedule_insns_after_reload, 1 }, + {"sched-interblock",&flag_schedule_interblock, 1 }, + {"sched-spec",&flag_schedule_speculative, 1 }, + {"sched-spec-load",&flag_schedule_speculative_load, 1 }, + {"sched-spec-load-dangerous",&flag_schedule_speculative_load_dangerous, 1 }, + {"sched-stalled-insns", &flag_sched_stalled_insns, 0 }, + {"sched-stalled-insns-dep", &flag_sched_stalled_insns_dep, 1 }, + {"sched2-use-superblocks", &flag_sched2_use_superblocks, 1 }, + {"sched2-use-traces", &flag_sched2_use_traces, 1 }, + {"branch-count-reg",&flag_branch_on_count_reg, 1 }, + {"pic", &flag_pic, 1 }, + {"PIC", &flag_pic, 2 }, + {"pie", &flag_pie, 1 }, + {"PIE", &flag_pie, 2 }, + {"exceptions", &flag_exceptions, 1 }, + {"unwind-tables", &flag_unwind_tables, 1 }, + {"asynchronous-unwind-tables", &flag_asynchronous_unwind_tables, 1 }, + {"non-call-exceptions", &flag_non_call_exceptions, 1 }, + {"profile-arcs", &profile_arc_flag, 1 }, + {"profile-values", &flag_profile_values, 1 }, + {"vpt", &flag_value_profile_transformations, 1 }, + {"test-coverage", &flag_test_coverage, 1 }, + {"branch-probabilities", &flag_branch_probabilities, 1 }, + {"profile", &profile_flag, 1 }, + {"reorder-blocks", &flag_reorder_blocks, 1 }, + {"reorder-functions", &flag_reorder_functions, 1 }, + {"rename-registers", &flag_rename_registers, 1 }, + {"cprop-registers", &flag_cprop_registers, 1 }, + {"common", &flag_no_common, 0 }, + {"inhibit-size-directive", &flag_inhibit_size_directive, 1 }, + {"function-sections", &flag_function_sections, 1 }, + {"data-sections", &flag_data_sections, 1 }, + {"verbose-asm", &flag_verbose_asm, 1 }, + {"regmove", &flag_regmove, 1 }, + {"optimize-register-move", &flag_regmove, 1 }, + {"pack-struct", &flag_pack_struct, 1 }, + {"stack-check", &flag_stack_check, 1 }, + {"argument-alias", &flag_argument_noalias, 0 }, + {"argument-noalias", &flag_argument_noalias, 1 }, + {"argument-noalias-global", &flag_argument_noalias, 2 }, + {"strict-aliasing", &flag_strict_aliasing, 1 }, + {"align-loops", &align_loops, 0 }, + {"align-jumps", &align_jumps, 0 }, + {"align-labels", &align_labels, 0 }, + {"align-functions", &align_functions, 0 }, + {"merge-constants", &flag_merge_constants, 1 }, + {"merge-all-constants", &flag_merge_constants, 2 }, + {"dump-unnumbered", &flag_dump_unnumbered, 1 }, + {"instrument-functions", &flag_instrument_function_entry_exit, 1 }, + {"zero-initialized-in-bss", &flag_zero_initialized_in_bss, 1 }, + {"leading-underscore", &flag_leading_underscore, 1 }, + {"ident", &flag_no_ident, 0 }, + { "peephole2", &flag_peephole2, 1 }, + {"finite-math-only", &flag_finite_math_only, 1 }, + { "guess-branch-probability", &flag_guess_branch_prob, 1 }, + {"math-errno", &flag_errno_math, 1 }, + {"trapping-math", &flag_trapping_math, 1 }, + {"rounding-math", &flag_rounding_math, 1 }, + {"unsafe-math-optimizations", &flag_unsafe_math_optimizations, 1 }, + {"signaling-nans", &flag_signaling_nans, 1 }, + {"bounds-check", &flag_bounds_check, 1 }, + {"single-precision-constant", &flag_single_precision_constant, 1 }, + {"time-report", &time_report, 1 }, + {"mem-report", &mem_report, 1 }, + { "trapv", &flag_trapv, 1 }, + { "wrapv", &flag_wrapv, 1 }, + { "new-ra", &flag_new_regalloc, 1 } +}; + +/* Here is a table, controlled by the tm.h file, listing each -m switch + and which bits in `target_switches' it should set or clear. + If VALUE is positive, it is bits to set. + If VALUE is negative, -VALUE is bits to clear. + (The sign bit is not used so there is no confusion.) */ + +static const struct +{ + const char *const name; + const int value; + const char *const description; +} +target_switches[] = TARGET_SWITCHES; + +/* This table is similar, but allows the switch to have a value. */ + +#ifdef TARGET_OPTIONS +static const struct +{ + const char *const prefix; + const char **const variable; + const char *const description; + const char *const value; +} +target_options[] = TARGET_OPTIONS; +#endif + +/* Nonzero means warn about function definitions that default the return type + or that use a null return and have a return-type other than void. */ + +int warn_return_type; + /* Output files for assembler code (real compiler output) and debugging dumps. */ FILE *asm_out_file; FILE *aux_info_file; -FILE *dump_file = NULL; -const char *dump_file_name; +FILE *rtl_dump_file = NULL; +FILE *cgraph_dump_file = NULL; /* The current working directory of a translation. It's generally the directory from which compilation was initiated, but a preprocessed @@ -417,12 +1219,7 @@ bool set_src_pwd (const char *pwd) { if (src_pwd) - { - if (strcmp (src_pwd, pwd) == 0) - return true; - else - return false; - } + return false; src_pwd = xstrdup (pwd); return true; @@ -436,11 +1233,7 @@ const char * get_src_pwd (void) { if (! src_pwd) - { - src_pwd = getpwd (); - if (!src_pwd) - src_pwd = "."; - } + src_pwd = getpwd (); return src_pwd; } @@ -453,9 +1246,9 @@ announce_function (tree decl) if (!quiet_flag) { if (rtl_dump_and_exit) - fprintf (stderr, "%s ", IDENTIFIER_POINTER (DECL_NAME (decl))); + verbatim ("%s ", IDENTIFIER_POINTER (DECL_NAME (decl))); else - fprintf (stderr, " %s", lang_hooks.decl_printable_name (decl, 2)); + verbatim (" %s", (*lang_hooks.decl_printable_name) (decl, 2)); fflush (stderr); pp_needs_newline (global_dc->printer) = true; diagnostic_set_last_function (global_dc); @@ -520,71 +1313,45 @@ read_integral_parameter (const char *p, const char *pname, const int defval) if (*endp != 0) { if (pname != 0) - error ("invalid option argument %qs", pname); + error ("invalid option argument `%s'", pname); return defval; } return atoi (p); } -/* When compiling with a recent enough GCC, we use the GNU C "extern inline" - for floor_log2 and exact_log2; see toplev.h. That construct, however, - conflicts with the ISO C++ One Definition Rule. */ - -#if GCC_VERSION < 3004 || !defined (__cplusplus) +/* Return the logarithm of X, base 2, considering X unsigned, + if X is a power of 2. Otherwise, returns -1. -/* Given X, an unsigned number, return the largest int Y such that 2**Y <= X. - If X is 0, return -1. */ + This should be used via the `exact_log2' macro. */ int -floor_log2 (unsigned HOST_WIDE_INT x) +exact_log2_wide (unsigned HOST_WIDE_INT x) { - int t = 0; - - if (x == 0) + int log = 0; + /* Test for 0 or a power of 2. */ + if (x == 0 || x != (x & -x)) return -1; - -#ifdef CLZ_HWI - t = HOST_BITS_PER_WIDE_INT - 1 - (int) CLZ_HWI (x); -#else - if (HOST_BITS_PER_WIDE_INT > 64) - if (x >= (unsigned HOST_WIDE_INT) 1 << (t + 64)) - t += 64; - if (HOST_BITS_PER_WIDE_INT > 32) - if (x >= ((unsigned HOST_WIDE_INT) 1) << (t + 32)) - t += 32; - if (x >= ((unsigned HOST_WIDE_INT) 1) << (t + 16)) - t += 16; - if (x >= ((unsigned HOST_WIDE_INT) 1) << (t + 8)) - t += 8; - if (x >= ((unsigned HOST_WIDE_INT) 1) << (t + 4)) - t += 4; - if (x >= ((unsigned HOST_WIDE_INT) 1) << (t + 2)) - t += 2; - if (x >= ((unsigned HOST_WIDE_INT) 1) << (t + 1)) - t += 1; -#endif - - return t; + while ((x >>= 1) != 0) + log++; + return log; } -/* Return the logarithm of X, base 2, considering X unsigned, - if X is a power of 2. Otherwise, returns -1. */ +/* Given X, an unsigned number, return the largest int Y such that 2**Y <= X. + If X is 0, return -1. + + This should be used via the floor_log2 macro. */ int -exact_log2 (unsigned HOST_WIDE_INT x) +floor_log2_wide (unsigned HOST_WIDE_INT x) { - if (x != (x & -x)) - return -1; -#ifdef CTZ_HWI - return x ? CTZ_HWI (x) : -1; -#else - return floor_log2 (x); -#endif + int log = -1; + while (x != 0) + log++, + x >>= 1; + return log; } -#endif /* GCC_VERSION < 3004 || !defined (__cplusplus) */ - /* Handler for fatal signals, such as SIGSEGV. These are transformed into ICE messages, which is much more user friendly. In case the error printer crashes, reset the signal to prevent infinite recursion. */ @@ -593,15 +1360,6 @@ static void crash_signal (int signo) { signal (signo, SIG_DFL); - - /* If we crashed while processing an ASM statement, then be a little more - graceful. It's most likely the user's fault. */ - if (this_is_asm_operands) - { - output_operand_lossage ("unrecoverable error"); - exit (FATAL_EXIT_CODE); - } - internal_error ("%s", strsignal (signo)); } @@ -704,88 +1462,94 @@ output_file_directive (FILE *asm_file, const char *input_name) #endif } -/* A subroutine of wrapup_global_declarations. We've come to the end of - the compilation unit. All deferred variables should be undeferred, - and all incomplete decls should be finalized. */ +/* Routine to open a dump file. Return true if the dump file is enabled. */ -void -wrapup_global_declaration_1 (tree decl) +static int +open_dump_file (enum dump_file_index index, tree decl) { - /* We're not deferring this any longer. Assignment is conditional to - avoid needlessly dirtying PCH pages. */ - if (CODE_CONTAINS_STRUCT (TREE_CODE (decl), TS_DECL_WITH_VIS) - && DECL_DEFER_OUTPUT (decl) != 0) - DECL_DEFER_OUTPUT (decl) = 0; + char *dump_name; + const char *open_arg; + char seq[16]; - if (TREE_CODE (decl) == VAR_DECL && DECL_SIZE (decl) == 0) - lang_hooks.finish_incomplete_decl (decl); -} + if (! dump_file[index].enabled) + return 0; -/* A subroutine of wrapup_global_declarations. Decide whether or not DECL - needs to be output. Return true if it is output. */ + timevar_push (TV_DUMP); + if (rtl_dump_file != NULL) + fclose (rtl_dump_file); -bool -wrapup_global_declaration_2 (tree decl) -{ - if (TREE_ASM_WRITTEN (decl) || DECL_EXTERNAL (decl)) - return false; + sprintf (seq, DUMPFILE_FORMAT, index); - /* Don't write out static consts, unless we still need them. - - We also keep static consts if not optimizing (for debugging), - unless the user specified -fno-keep-static-consts. - ??? They might be better written into the debug information. - This is possible when using DWARF. - - A language processor that wants static constants to be always - written out (even if it is not used) is responsible for - calling rest_of_decl_compilation itself. E.g. the C front-end - calls rest_of_decl_compilation from finish_decl. - One motivation for this is that is conventional in some - environments to write things like: - static const char rcsid[] = "... version string ..."; - intending to force the string to be in the executable. - - A language processor that would prefer to have unneeded - static constants "optimized away" would just defer writing - them out until here. E.g. C++ does this, because static - constants are often defined in header files. - - ??? A tempting alternative (for both C and C++) would be - to force a constant to be written if and only if it is - defined in a main file, as opposed to an include file. */ - - if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) - { - struct cgraph_varpool_node *node; - bool needed = true; - node = cgraph_varpool_node (decl); - - if (node->finalized) - needed = false; - else if (node->alias) - needed = false; - else if (!cgraph_global_info_ready - && (TREE_USED (decl) - || TREE_USED (DECL_ASSEMBLER_NAME (decl)))) - /* needed */; - else if (node->needed) - /* needed */; - else if (DECL_COMDAT (decl)) - needed = false; - else if (TREE_READONLY (decl) && !TREE_PUBLIC (decl) - && (optimize || !flag_keep_static_consts - || DECL_ARTIFICIAL (decl))) - needed = false; - - if (needed) + if (! dump_file[index].initialized) + { + /* If we've not initialized the files, do so now. */ + if (graph_dump_format != no_graph + && dump_file[index].graph_dump_p) { - rest_of_decl_compilation (decl, 1, 1); - return true; + dump_name = concat (seq, dump_file[index].extension, NULL); + clean_graph_dump_file (dump_base_name, dump_name); + free (dump_name); } + dump_file[index].initialized = 1; + open_arg = "w"; } + else + open_arg = "a"; - return false; + dump_name = concat (dump_base_name, seq, + dump_file[index].extension, NULL); + + rtl_dump_file = fopen (dump_name, open_arg); + if (rtl_dump_file == NULL) + fatal_error ("can't open %s: %m", dump_name); + + free (dump_name); + + if (decl) + fprintf (rtl_dump_file, "\n;; Function %s%s\n\n", + (*lang_hooks.decl_printable_name) (decl, 2), + cfun->function_frequency == FUNCTION_FREQUENCY_HOT + ? " (hot)" + : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED + ? " (unlikely executed)" + : ""); + + timevar_pop (TV_DUMP); + return 1; +} + +/* Routine to close a dump file. */ + +static void +close_dump_file (enum dump_file_index index, + void (*func) (FILE *, rtx), + rtx insns) +{ + if (! rtl_dump_file) + return; + + timevar_push (TV_DUMP); + if (insns + && graph_dump_format != no_graph + && dump_file[index].graph_dump_p) + { + char seq[16]; + char *suffix; + + sprintf (seq, DUMPFILE_FORMAT, index); + suffix = concat (seq, dump_file[index].extension, NULL); + print_rtl_graph_with_bb (dump_base_name, suffix, insns); + free (suffix); + } + + if (func && insns) + func (rtl_dump_file, insns); + + fflush (rtl_dump_file); + fclose (rtl_dump_file); + + rtl_dump_file = NULL; + timevar_pop (TV_DUMP); } /* Do any final processing required for the declarations in VEC, of @@ -793,107 +1557,185 @@ wrapup_global_declaration_2 (tree decl) that have been deferred until this point, but which are required. Returns nonzero if anything was put out. */ -bool +int wrapup_global_declarations (tree *vec, int len) { - bool reconsider, output_something = false; + tree decl; int i; + int reconsider; + int output_something = 0; for (i = 0; i < len; i++) - wrapup_global_declaration_1 (vec[i]); + { + decl = vec[i]; + + /* We're not deferring this any longer. Assignment is + conditional to avoid needlessly dirtying PCH pages. */ + if (DECL_DEFER_OUTPUT (decl) != 0) + DECL_DEFER_OUTPUT (decl) = 0; + + if (TREE_CODE (decl) == VAR_DECL && DECL_SIZE (decl) == 0) + (*lang_hooks.finish_incomplete_decl) (decl); + } /* Now emit any global variables or functions that we have been putting off. We need to loop in case one of the things emitted here references another one which comes earlier in the list. */ do { - reconsider = false; + reconsider = 0; for (i = 0; i < len; i++) - reconsider |= wrapup_global_declaration_2 (vec[i]); + { + decl = vec[i]; + + if (TREE_ASM_WRITTEN (decl) || DECL_EXTERNAL (decl)) + continue; + + /* Don't write out static consts, unless we still need them. + + We also keep static consts if not optimizing (for debugging), + unless the user specified -fno-keep-static-consts. + ??? They might be better written into the debug information. + This is possible when using DWARF. + + A language processor that wants static constants to be always + written out (even if it is not used) is responsible for + calling rest_of_decl_compilation itself. E.g. the C front-end + calls rest_of_decl_compilation from finish_decl. + One motivation for this is that is conventional in some + environments to write things like: + static const char rcsid[] = "... version string ..."; + intending to force the string to be in the executable. + + A language processor that would prefer to have unneeded + static constants "optimized away" would just defer writing + them out until here. E.g. C++ does this, because static + constants are often defined in header files. + + ??? A tempting alternative (for both C and C++) would be + to force a constant to be written if and only if it is + defined in a main file, as opposed to an include file. */ + + if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) + { + bool needed = 1; + + if (flag_unit_at_a_time + && cgraph_varpool_node (decl)->finalized) + needed = 0; + else if ((flag_unit_at_a_time && !cgraph_global_info_ready) + && (TREE_USED (decl) + || TREE_USED (DECL_ASSEMBLER_NAME (decl)))) + /* needed */; + else if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) + /* needed */; + else if (DECL_COMDAT (decl)) + needed = 0; + else if (TREE_READONLY (decl) && !TREE_PUBLIC (decl) + && (optimize || !flag_keep_static_consts + || DECL_ARTIFICIAL (decl))) + needed = 0; + + if (needed) + { + reconsider = 1; + rest_of_decl_compilation (decl, NULL, 1, 1); + } + } + + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_INITIAL (decl) != 0 + && DECL_SAVED_INSNS (decl) != 0 + && DECL_SAVED_INSNS (decl)->saved_for_inline + && (flag_keep_inline_functions + || (TREE_PUBLIC (decl) && !DECL_COMDAT (decl)) + || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) + { + reconsider = 1; + output_inline_function (decl); + } + } + if (reconsider) - output_something = true; + output_something = 1; } while (reconsider); return output_something; } -/* A subroutine of check_global_declarations. Issue appropriate warnings - for the global declaration DECL. */ - -void -check_global_declaration_1 (tree decl) -{ - /* Warn about any function declared static but not defined. We don't - warn about variables, because many programs have static variables - that exist only to get some text into the object file. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_INITIAL (decl) == 0 - && DECL_EXTERNAL (decl) - && ! DECL_ARTIFICIAL (decl) - && ! TREE_NO_WARNING (decl) - && ! TREE_PUBLIC (decl) - && (warn_unused_function - || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) - { - if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) - pedwarn ("%q+F used but never defined", decl); - else - warning (0, "%q+F declared %<static%> but never defined", decl); - /* This symbol is effectively an "extern" declaration now. */ - TREE_PUBLIC (decl) = 1; - assemble_external (decl); - } - - /* Warn about static fns or vars defined but not used. */ - if (((warn_unused_function && TREE_CODE (decl) == FUNCTION_DECL) - /* We don't warn about "static const" variables because the - "rcs_id" idiom uses that construction. */ - || (warn_unused_variable - && TREE_CODE (decl) == VAR_DECL && ! TREE_READONLY (decl))) - && ! DECL_IN_SYSTEM_HEADER (decl) - && ! TREE_USED (decl) - /* The TREE_USED bit for file-scope decls is kept in the identifier, - to handle multiple external decls in different scopes. */ - && ! (DECL_NAME (decl) && TREE_USED (DECL_NAME (decl))) - && ! DECL_EXTERNAL (decl) - && ! TREE_PUBLIC (decl) - /* A volatile variable might be used in some non-obvious way. */ - && ! TREE_THIS_VOLATILE (decl) - /* Global register variables must be declared to reserve them. */ - && ! (TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)) - /* Otherwise, ask the language. */ - && lang_hooks.decls.warn_unused_global (decl)) - warning (0, "%q+D defined but not used", decl); -} - /* Issue appropriate warnings for the global declarations in VEC (of - which there are LEN). */ + which there are LEN). Output debugging information for them. */ void check_global_declarations (tree *vec, int len) { + tree decl; int i; for (i = 0; i < len; i++) - check_global_declaration_1 (vec[i]); -} - -/* Emit debugging information for all global declarations in VEC. */ - -void -emit_debug_global_declarations (tree *vec, int len) -{ - int i; - - /* Avoid confusing the debug information machinery when there are errors. */ - if (errorcount != 0 || sorrycount != 0) - return; + { + decl = vec[i]; + + if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl) + && ! TREE_ASM_WRITTEN (decl)) + /* Cancel the RTL for this decl so that, if debugging info + output for global variables is still to come, + this one will be omitted. */ + SET_DECL_RTL (decl, NULL_RTX); + + /* Warn about any function + declared static but not defined. + We don't warn about variables, + because many programs have static variables + that exist only to get some text into the object file. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && (warn_unused_function + || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) + && DECL_INITIAL (decl) == 0 + && DECL_EXTERNAL (decl) + && ! DECL_ARTIFICIAL (decl) + && ! TREE_PUBLIC (decl)) + { + if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) + pedwarn ("%J'%F' used but never defined", decl, decl); + else + warning ("%J'%F' declared `static' but never defined", decl, decl); + /* This symbol is effectively an "extern" declaration now. */ + TREE_PUBLIC (decl) = 1; + assemble_external (decl); + } - timevar_push (TV_SYMOUT); - for (i = 0; i < len; i++) - debug_hooks->global_decl (vec[i]); - timevar_pop (TV_SYMOUT); + /* Warn about static fns or vars defined but not used. */ + if (((warn_unused_function && TREE_CODE (decl) == FUNCTION_DECL) + /* We don't warn about "static const" variables because the + "rcs_id" idiom uses that construction. */ + || (warn_unused_variable + && TREE_CODE (decl) == VAR_DECL && ! TREE_READONLY (decl))) + && ! DECL_IN_SYSTEM_HEADER (decl) + && ! TREE_USED (decl) + /* The TREE_USED bit for file-scope decls is kept in the identifier, + to handle multiple external decls in different scopes. */ + && ! TREE_USED (DECL_NAME (decl)) + && ! DECL_EXTERNAL (decl) + && ! TREE_PUBLIC (decl) + /* A volatile variable might be used in some non-obvious way. */ + && ! TREE_THIS_VOLATILE (decl) + /* Global register variables must be declared to reserve them. */ + && ! (TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)) + /* Otherwise, ask the language. */ + && (*lang_hooks.decls.warn_unused_global) (decl)) + warning ("%J'%D' defined but not used", decl, decl); + + /* Avoid confusing the debug information machinery when there are + errors. */ + if (errorcount == 0 && sorrycount == 0) + { + timevar_push (TV_SYMOUT); + (*debug_hooks->global_decl) (decl); + timevar_pop (TV_SYMOUT); + } + } } /* Warn about a use of an identifier which was marked deprecated. */ @@ -904,47 +1746,33 @@ warn_deprecated_use (tree node) return; if (DECL_P (node)) - { - expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (node)); - warning (OPT_Wdeprecated_declarations, - "%qs is deprecated (declared at %s:%d)", - IDENTIFIER_POINTER (DECL_NAME (node)), - xloc.file, xloc.line); - } + warning ("`%s' is deprecated (declared at %s:%d)", + IDENTIFIER_POINTER (DECL_NAME (node)), + DECL_SOURCE_FILE (node), DECL_SOURCE_LINE (node)); else if (TYPE_P (node)) { const char *what = NULL; tree decl = TYPE_STUB_DECL (node); - if (TYPE_NAME (node)) - { - if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) - what = IDENTIFIER_POINTER (TYPE_NAME (node)); - else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (node))) - what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))); - } + if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) + what = IDENTIFIER_POINTER (TYPE_NAME (node)); + else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (node))) + what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))); - if (decl) + if (what) { - expanded_location xloc - = expand_location (DECL_SOURCE_LOCATION (decl)); - if (what) - warning (OPT_Wdeprecated_declarations, - "%qs is deprecated (declared at %s:%d)", what, - xloc.file, xloc.line); + if (decl) + warning ("`%s' is deprecated (declared at %s:%d)", what, + DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); else - warning (OPT_Wdeprecated_declarations, - "type is deprecated (declared at %s:%d)", - xloc.file, xloc.line); + warning ("`%s' is deprecated", what); } + else if (decl) + warning ("type is deprecated (declared at %s:%d)", + DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); else - { - if (what) - warning (OPT_Wdeprecated_declarations, "%qs is deprecated", what); - else - warning (OPT_Wdeprecated_declarations, "type is deprecated"); - } + warning ("type is deprecated"); } } @@ -953,30 +1781,17 @@ warn_deprecated_use (tree node) INPUT_LOCATION accordingly. */ void -#ifdef USE_MAPPED_LOCATION -push_srcloc (location_t fline) -#else push_srcloc (const char *file, int line) -#endif { struct file_stack *fs; - gcc_assert (!input_file_stack_restored); - if (input_file_stack_tick == (int) ((1U << INPUT_FILE_STACK_BITS) - 1)) - sorry ("GCC supports only %d input file changes", input_file_stack_tick); - - fs = XNEW (struct file_stack); + fs = xmalloc (sizeof (struct file_stack)); fs->location = input_location; fs->next = input_file_stack; -#ifdef USE_MAPPED_LOCATION - input_location = fline; -#else input_filename = file; input_line = line; -#endif input_file_stack = fs; input_file_stack_tick++; - VEC_safe_push (fs_p, heap, input_file_stack_history, input_file_stack); } /* Pop the top entry off the stack of presently open source files. @@ -988,30 +1803,11 @@ pop_srcloc (void) { struct file_stack *fs; - gcc_assert (!input_file_stack_restored); - if (input_file_stack_tick == (int) ((1U << INPUT_FILE_STACK_BITS) - 1)) - sorry ("GCC supports only %d input file changes", input_file_stack_tick); - fs = input_file_stack; input_location = fs->location; input_file_stack = fs->next; + free (fs); input_file_stack_tick++; - VEC_safe_push (fs_p, heap, input_file_stack_history, input_file_stack); -} - -/* Restore the input file stack to its state as of TICK, for the sake - of diagnostics after processing the whole input. Once this has - been called, push_srcloc and pop_srcloc may no longer be - called. */ -void -restore_input_file_stack (int tick) -{ - if (tick == 0) - input_file_stack = NULL; - else - input_file_stack = VEC_index (fs_p, input_file_stack_history, tick - 1); - input_file_stack_tick = tick; - input_file_stack_restored = true; } /* Compile an entire translation unit. Write a file of assembly @@ -1022,7 +1818,6 @@ compile_file (void) { /* Initialize yet another pass. */ - init_cgraph (); init_final (main_input_filename); coverage_init (aux_base_name); @@ -1030,35 +1825,28 @@ compile_file (void) /* Call the parser, which parses the entire file (calling rest_of_compilation for each function). */ - lang_hooks.parse_file (set_yydebug); + (*lang_hooks.parse_file) (set_yydebug); /* In case there were missing block closers, get us back to the global binding level. */ - lang_hooks.clear_binding_stack (); + (*lang_hooks.clear_binding_stack) (); /* Compilation is now finished except for writing what's left of the symbol table output. */ timevar_pop (TV_PARSE); - if (flag_syntax_only || errorcount || sorrycount) + if (flag_syntax_only) return; - lang_hooks.decls.final_write_globals (); + (*lang_hooks.decls.final_write_globals)(); + cgraph_varpool_assemble_pending_decls (); - finish_aliases_2 (); /* This must occur after the loop to output deferred functions. Else the coverage initializer would not be emitted if all the functions in this compilation unit were deferred. */ coverage_finish (); - /* Likewise for mudflap static object registrations. */ - if (flag_mudflap) - mudflap_finish_file (); - - output_shared_constant_pool (); - output_object_blocks (); - /* Write out any pending weak symbol declarations. */ weak_finish (); @@ -1066,7 +1854,7 @@ compile_file (void) /* Do dbx symbols. */ timevar_push (TV_SYMOUT); -#if defined DWARF2_DEBUGGING_INFO || defined DWARF2_UNWIND_INFO +#ifdef DWARF2_UNWIND_INFO if (dwarf2out_do_frame ()) dwarf2out_frame_finish (); #endif @@ -1078,10 +1866,21 @@ compile_file (void) dw2_output_indirect_constants (); - /* Flush any pending external directives. cgraph did this for - assemble_external calls from the front end, but the RTL - expander can also generate them. */ - process_pending_assemble_externals (); + /* Flush any pending equate directives. */ + process_pending_assemble_output_defs (); + + if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities) + { + timevar_push (TV_DUMP); + open_dump_file (DFI_bp, NULL); + + end_branch_prob (); + + close_dump_file (DFI_bp, NULL, NULL_RTX); + timevar_pop (TV_DUMP); + } + + targetm.asm_out.file_end (); /* Attach a special .ident directive to the end of the file to identify the version of GCC which compiled this code. The format of the .ident @@ -1092,10 +1891,1881 @@ compile_file (void) IDENT_ASM_OP, version_string); #endif - /* This must be at the end. Some target ports emit end of file directives - into the assembly file here, and hence we can not output anything to the - assembly file after this point. */ - targetm.asm_out.file_end (); + if (optimize > 0 && open_dump_file (DFI_combine, NULL)) + { + timevar_push (TV_DUMP); + dump_combine_total_stats (rtl_dump_file); + close_dump_file (DFI_combine, NULL, NULL_RTX); + timevar_pop (TV_DUMP); + } +} + +/* This is called from various places for FUNCTION_DECL, VAR_DECL, + and TYPE_DECL nodes. + + This does nothing for local (non-static) variables, unless the + variable is a register variable with an ASMSPEC. In that case, or + if the variable is not an automatic, it sets up the RTL and + outputs any assembler code (label definition, storage allocation + and initialization). + + DECL is the declaration. If ASMSPEC is nonzero, it specifies + the assembler symbol name to be used. TOP_LEVEL is nonzero + if this declaration is not within a function. */ + +void +rest_of_decl_compilation (tree decl, + const char *asmspec, + int top_level, + int at_end) +{ + /* We deferred calling assemble_alias so that we could collect + other attributes such as visibility. Emit the alias now. */ + { + tree alias; + alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl)); + if (alias) + { + alias = TREE_VALUE (TREE_VALUE (alias)); + alias = get_identifier (TREE_STRING_POINTER (alias)); + assemble_alias (decl, alias); + } + } + + /* Forward declarations for nested functions are not "external", + but we need to treat them as if they were. */ + if (TREE_STATIC (decl) || DECL_EXTERNAL (decl) + || TREE_CODE (decl) == FUNCTION_DECL) + { + timevar_push (TV_VARCONST); + + if (asmspec) + make_decl_rtl (decl, asmspec); + + /* Don't output anything when a tentative file-scope definition + is seen. But at end of compilation, do output code for them. + + We do output all variables when unit-at-a-time is active and rely on + callgraph code to defer them except for forward declarations + (see gcc.c-torture/compile/920624-1.c) */ + if ((at_end + || !DECL_DEFER_OUTPUT (decl) + || (flag_unit_at_a_time && DECL_INITIAL (decl))) + && !DECL_EXTERNAL (decl)) + { + if (flag_unit_at_a_time && !cgraph_global_info_ready + && TREE_CODE (decl) != FUNCTION_DECL && top_level) + cgraph_varpool_finalize_decl (decl); + else + assemble_variable (decl, top_level, at_end, 0); + } + +#ifdef ASM_FINISH_DECLARE_OBJECT + if (decl == last_assemble_variable_decl) + { + ASM_FINISH_DECLARE_OBJECT (asm_out_file, decl, + top_level, at_end); + } +#endif + + timevar_pop (TV_VARCONST); + } + else if (DECL_REGISTER (decl) && asmspec != 0) + { + if (decode_reg_name (asmspec) >= 0) + { + SET_DECL_RTL (decl, NULL_RTX); + make_decl_rtl (decl, asmspec); + } + else + { + error ("invalid register name `%s' for register variable", asmspec); + DECL_REGISTER (decl) = 0; + if (!top_level) + expand_decl (decl); + } + } +#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) + else if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) + && TREE_CODE (decl) == TYPE_DECL) + { + timevar_push (TV_SYMOUT); + dbxout_symbol (decl, 0); + timevar_pop (TV_SYMOUT); + } +#endif +#ifdef SDB_DEBUGGING_INFO + else if (write_symbols == SDB_DEBUG && top_level + && TREE_CODE (decl) == TYPE_DECL) + { + timevar_push (TV_SYMOUT); + sdbout_symbol (decl, 0); + timevar_pop (TV_SYMOUT); + } +#endif +#ifdef DWARF2_DEBUGGING_INFO + else if ((write_symbols == DWARF2_DEBUG + || write_symbols == VMS_AND_DWARF2_DEBUG) + && top_level + && TREE_CODE (decl) == TYPE_DECL) + { + timevar_push (TV_SYMOUT); + dwarf2out_decl (decl); + timevar_pop (TV_SYMOUT); + } +#endif +} + +/* Called after finishing a record, union or enumeral type. */ + +void +rest_of_type_compilation ( +#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) \ + || defined (SDB_DEBUGGING_INFO) || defined (DWARF2_DEBUGGING_INFO) + tree type, + int toplev +#else + tree type ATTRIBUTE_UNUSED, + int toplev ATTRIBUTE_UNUSED +#endif + ) +{ + /* Avoid confusing the debug information machinery when there are + errors. */ + if (errorcount != 0 || sorrycount != 0) + return; + + timevar_push (TV_SYMOUT); +#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) + if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) + dbxout_symbol (TYPE_STUB_DECL (type), !toplev); +#endif +#ifdef SDB_DEBUGGING_INFO + if (write_symbols == SDB_DEBUG) + sdbout_symbol (TYPE_STUB_DECL (type), !toplev); +#endif +#ifdef DWARF2_DEBUGGING_INFO + if ((write_symbols == DWARF2_DEBUG + || write_symbols == VMS_AND_DWARF2_DEBUG) + && toplev) + dwarf2out_decl (TYPE_STUB_DECL (type)); +#endif + timevar_pop (TV_SYMOUT); +} + +/* Turn the RTL into assembly. */ +static void +rest_of_handle_final (tree decl, rtx insns) +{ + timevar_push (TV_FINAL); + { + rtx x; + const char *fnname; + + /* Get the function's name, as described by its RTL. This may be + different from the DECL_NAME name used in the source file. */ + + x = DECL_RTL (decl); + if (GET_CODE (x) != MEM) + abort (); + x = XEXP (x, 0); + if (GET_CODE (x) != SYMBOL_REF) + abort (); + fnname = XSTR (x, 0); + + assemble_start_function (decl, fnname); + final_start_function (insns, asm_out_file, optimize); + final (insns, asm_out_file, optimize, 0); + final_end_function (); + +#ifdef IA64_UNWIND_INFO + /* ??? The IA-64 ".handlerdata" directive must be issued before + the ".endp" directive that closes the procedure descriptor. */ + output_function_exception_table (); +#endif + + assemble_end_function (decl, fnname); + +#ifndef IA64_UNWIND_INFO + /* Otherwise, it feels unclean to switch sections in the middle. */ + output_function_exception_table (); +#endif + + if (! quiet_flag) + fflush (asm_out_file); + + /* Release all memory allocated by flow. */ + free_basic_block_vars (0); + + /* Release all memory held by regsets now. */ + regset_release_memory (); + } + timevar_pop (TV_FINAL); + + ggc_collect (); +} + +#ifdef DELAY_SLOTS +/* Run delay slot optimization. */ +static void +rest_of_handle_delay_slots (tree decl, rtx insns) +{ + timevar_push (TV_DBR_SCHED); + open_dump_file (DFI_dbr, decl); + + dbr_schedule (insns, rtl_dump_file); + + close_dump_file (DFI_dbr, print_rtl, insns); + timevar_pop (TV_DBR_SCHED); + + ggc_collect (); +} +#endif + +#ifdef STACK_REGS +/* Convert register usage from flat register file usage to a stack + register file. */ +static void +rest_of_handle_stack_regs (tree decl, rtx insns) +{ +#if defined (HAVE_ATTR_length) + /* If flow2 creates new instructions which need splitting + and scheduling after reload is not done, they might not be + split until final which doesn't allow splitting + if HAVE_ATTR_length. */ +#ifdef INSN_SCHEDULING + if (optimize && !flag_schedule_insns_after_reload) +#else + if (optimize) +#endif + { + timevar_push (TV_SHORTEN_BRANCH); + split_all_insns (1); + timevar_pop (TV_SHORTEN_BRANCH); + } +#endif + + timevar_push (TV_REG_STACK); + open_dump_file (DFI_stack, decl); + + if (reg_to_stack (insns, rtl_dump_file) && optimize) + { + if (cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK + | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0)) + && flag_reorder_blocks) + { + reorder_basic_blocks (0); + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK); + } + } + + close_dump_file (DFI_stack, print_rtl_with_bb, insns); + timevar_pop (TV_REG_STACK); + + ggc_collect (); +} +#endif + + +/* Machine independent reorg pass. */ +static void +rest_of_handle_machine_reorg (tree decl, rtx insns) +{ + timevar_push (TV_MACH_DEP); + open_dump_file (DFI_mach, decl); + + (*targetm.machine_dependent_reorg) (); + + close_dump_file (DFI_mach, print_rtl, insns); + timevar_pop (TV_MACH_DEP); + + ggc_collect (); +} + + +/* Run new register allocator. Return TRUE if we must exit + rest_of_compilation upon return. */ +static bool +rest_of_handle_new_regalloc (tree decl, rtx insns) +{ + int failure; + + delete_trivially_dead_insns (insns, max_reg_num ()); + reg_alloc (); + + timevar_pop (TV_LOCAL_ALLOC); + if (dump_file[DFI_lreg].enabled) + { + timevar_push (TV_DUMP); + + close_dump_file (DFI_lreg, NULL, NULL); + timevar_pop (TV_DUMP); + } + + /* XXX clean up the whole mess to bring live info in shape again. */ + timevar_push (TV_GLOBAL_ALLOC); + open_dump_file (DFI_greg, decl); + + build_insn_chain (insns); + failure = reload (insns, 0); + + timevar_pop (TV_GLOBAL_ALLOC); + + if (dump_file[DFI_greg].enabled) + { + timevar_push (TV_DUMP); + + dump_global_regs (rtl_dump_file); + + close_dump_file (DFI_greg, print_rtl_with_bb, insns); + timevar_pop (TV_DUMP); + } + + if (failure) + return true; + + reload_completed = 1; + + return false; +} + +/* Run old register allocator. Return TRUE if we must exit + rest_of_compilation upon return. */ +static bool +rest_of_handle_old_regalloc (tree decl, rtx insns) +{ + int failure; + int rebuild_notes; + + /* Allocate the reg_renumber array. */ + allocate_reg_info (max_regno, FALSE, TRUE); + + /* And the reg_equiv_memory_loc array. */ + reg_equiv_memory_loc = xcalloc (max_regno, sizeof (rtx)); + + allocate_initial_values (reg_equiv_memory_loc); + + regclass (insns, max_reg_num (), rtl_dump_file); + rebuild_notes = local_alloc (); + + timevar_pop (TV_LOCAL_ALLOC); + + /* Local allocation may have turned an indirect jump into a direct + jump. If so, we must rebuild the JUMP_LABEL fields of jumping + instructions. */ + if (rebuild_notes) + { + timevar_push (TV_JUMP); + + rebuild_jump_labels (insns); + purge_all_dead_edges (0); + + timevar_pop (TV_JUMP); + } + + if (dump_file[DFI_lreg].enabled) + { + timevar_push (TV_DUMP); + + dump_flow_info (rtl_dump_file); + dump_local_alloc (rtl_dump_file); + + close_dump_file (DFI_lreg, print_rtl_with_bb, insns); + timevar_pop (TV_DUMP); + } + + ggc_collect (); + + timevar_push (TV_GLOBAL_ALLOC); + open_dump_file (DFI_greg, decl); + + /* If optimizing, allocate remaining pseudo-regs. Do the reload + pass fixing up any insns that are invalid. */ + + if (optimize) + failure = global_alloc (rtl_dump_file); + else + { + build_insn_chain (insns); + failure = reload (insns, 0); + } + + timevar_pop (TV_GLOBAL_ALLOC); + + if (dump_file[DFI_greg].enabled) + { + timevar_push (TV_DUMP); + + dump_global_regs (rtl_dump_file); + + close_dump_file (DFI_greg, print_rtl_with_bb, insns); + timevar_pop (TV_DUMP); + } + + return failure; +} + +/* Run the regrename and cprop passes. */ +static void +rest_of_handle_regrename (tree decl, rtx insns) +{ + timevar_push (TV_RENAME_REGISTERS); + open_dump_file (DFI_rnreg, decl); + + if (flag_rename_registers) + regrename_optimize (); + if (flag_cprop_registers) + copyprop_hardreg_forward (); + + close_dump_file (DFI_rnreg, print_rtl_with_bb, insns); + timevar_pop (TV_RENAME_REGISTERS); +} + +/* Reorder basic blocks. */ +static void +rest_of_handle_reorder_blocks (tree decl, rtx insns) +{ + bool changed; + unsigned int liveness_flags; + + open_dump_file (DFI_bbro, decl); + + /* Last attempt to optimize CFG, as scheduling, peepholing and insn + splitting possibly introduced more crossjumping opportunities. */ + liveness_flags = (!HAVE_conditional_execution ? CLEANUP_UPDATE_LIFE : 0); + changed = cleanup_cfg (CLEANUP_EXPENSIVE | liveness_flags); + + if (flag_sched2_use_traces && flag_schedule_insns_after_reload) + tracer (liveness_flags); + if (flag_reorder_blocks) + reorder_basic_blocks (liveness_flags); + if (flag_reorder_blocks + || (flag_sched2_use_traces && flag_schedule_insns_after_reload)) + changed |= cleanup_cfg (CLEANUP_EXPENSIVE | liveness_flags); + + /* On conditional execution targets we can not update the life cheaply, so + we deffer the updating to after both cleanups. This may lose some cases + but should not be terribly bad. */ + if (changed && HAVE_conditional_execution) + update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES, + PROP_DEATH_NOTES | PROP_REG_INFO); + close_dump_file (DFI_bbro, print_rtl_with_bb, insns); +} + +#ifdef INSN_SCHEDULING +/* Run instruction scheduler. */ +static void +rest_of_handle_sched (tree decl, rtx insns) +{ + timevar_push (TV_SCHED); + + /* Print function header into sched dump now + because doing the sched analysis makes some of the dump. */ + if (optimize > 0 && flag_schedule_insns) + { + open_dump_file (DFI_sched, decl); + + /* Do control and data sched analysis, + and write some of the results to dump file. */ + + schedule_insns (rtl_dump_file); + + close_dump_file (DFI_sched, print_rtl_with_bb, insns); + } + timevar_pop (TV_SCHED); + + ggc_collect (); +} + +/* Run second scheduling pass after reload. */ +static void +rest_of_handle_sched2 (tree decl, rtx insns) +{ + timevar_push (TV_SCHED2); + open_dump_file (DFI_sched2, decl); + + /* Do control and data sched analysis again, + and write some more of the results to dump file. */ + + split_all_insns (1); + + if (flag_sched2_use_superblocks || flag_sched2_use_traces) + { + schedule_ebbs (rtl_dump_file); + /* No liveness updating code yet, but it should be easy to do. + reg-stack recompute the liveness when needed for now. */ + count_or_remove_death_notes (NULL, 1); + cleanup_cfg (CLEANUP_EXPENSIVE); + } + else + schedule_insns (rtl_dump_file); + + close_dump_file (DFI_sched2, print_rtl_with_bb, insns); + timevar_pop (TV_SCHED2); + + ggc_collect (); +} +#endif + +/* Register allocation pre-pass, to reduce number of moves necessary + for two-address machines. */ +static void +rest_of_handle_regmove (tree decl, rtx insns) +{ + timevar_push (TV_REGMOVE); + open_dump_file (DFI_regmove, decl); + + regmove_optimize (insns, max_reg_num (), rtl_dump_file); + + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); + close_dump_file (DFI_regmove, print_rtl_with_bb, insns); + timevar_pop (TV_REGMOVE); + + ggc_collect (); +} + +/* Run tracer. */ +static void +rest_of_handle_tracer (tree decl, rtx insns) +{ + open_dump_file (DFI_tracer, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + tracer (0); + cleanup_cfg (CLEANUP_EXPENSIVE); + reg_scan (insns, max_reg_num (), 0); + close_dump_file (DFI_tracer, print_rtl_with_bb, get_insns ()); +} + +/* If-conversion and CFG cleanup. */ +static void +rest_of_handle_if_conversion (tree decl, rtx insns) +{ + open_dump_file (DFI_ce1, decl); + if (flag_if_conversion) + { + timevar_push (TV_IFCVT); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + cleanup_cfg (CLEANUP_EXPENSIVE); + reg_scan (insns, max_reg_num (), 0); + if_convert (0); + timevar_pop (TV_IFCVT); + } + timevar_push (TV_JUMP); + cleanup_cfg (CLEANUP_EXPENSIVE); + reg_scan (insns, max_reg_num (), 0); + timevar_pop (TV_JUMP); + close_dump_file (DFI_ce1, print_rtl_with_bb, get_insns ()); +} + +/* Rerun if-conversion, as combine may have simplified things enough + to now meet sequence length restrictions. */ +static void +rest_of_handle_if_after_combine (tree decl, rtx insns) +{ + timevar_push (TV_IFCVT); + open_dump_file (DFI_ce2, decl); + + no_new_pseudos = 0; + if_convert (1); + no_new_pseudos = 1; + + close_dump_file (DFI_ce2, print_rtl_with_bb, insns); + timevar_pop (TV_IFCVT); +} + +static void +rest_of_handle_web (tree decl, rtx insns) +{ + open_dump_file (DFI_web, decl); + timevar_push (TV_WEB); + web_main (); + delete_trivially_dead_insns (insns, max_reg_num ()); + cleanup_cfg (CLEANUP_EXPENSIVE); + + timevar_pop (TV_WEB); + close_dump_file (DFI_web, print_rtl_with_bb, insns); + reg_scan (get_insns (), max_reg_num (), 0); +} + +/* Do branch profiling and static profile estimation passes. */ +static void +rest_of_handle_branch_prob (tree decl, rtx insns) +{ + struct loops loops; + + timevar_push (TV_BRANCH_PROB); + open_dump_file (DFI_bp, decl); + + if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities) + branch_prob (); + + /* Discover and record the loop depth at the head of each basic + block. The loop infrastructure does the real job for us. */ + flow_loops_find (&loops, LOOP_TREE); + + if (rtl_dump_file) + flow_loops_dump (&loops, rtl_dump_file, NULL, 0); + + /* Estimate using heuristics if no profiling info is available. */ + if (flag_guess_branch_prob) + estimate_probability (&loops); + + flow_loops_free (&loops); + free_dominance_info (CDI_DOMINATORS); + close_dump_file (DFI_bp, print_rtl_with_bb, insns); + timevar_pop (TV_BRANCH_PROB); +} + +/* Do optimizations based on expression value profiles. */ +static void +rest_of_handle_value_profile_transformations (tree decl, rtx insns) +{ + open_dump_file (DFI_vpt, decl); + timevar_push (TV_VPT); + + if (value_profile_transformations ()) + cleanup_cfg (CLEANUP_EXPENSIVE); + + timevar_pop (TV_VPT); + close_dump_file (DFI_vpt, print_rtl_with_bb, insns); +} + +/* Do control and data flow analysis; write some of the results to the + dump file. */ +static void +rest_of_handle_cfg (tree decl, rtx insns) +{ + open_dump_file (DFI_cfg, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + if (optimize) + cleanup_cfg (CLEANUP_EXPENSIVE + | (flag_thread_jumps ? CLEANUP_THREADING : 0)); + + /* It may make more sense to mark constant functions after dead code is + eliminated by life_analysis, but we need to do it early, as -fprofile-arcs + may insert code making function non-constant, but we still must consider + it as constant, otherwise -fbranch-probabilities will not read data back. + + life_analysis rarely eliminates modification of external memory. + */ + if (optimize) + { + /* Alias analysis depends on this information and mark_constant_function + depends on alias analysis. */ + reg_scan (insns, max_reg_num (), 1); + mark_constant_function (); + } + + close_dump_file (DFI_cfg, print_rtl_with_bb, insns); +} + +/* Purge addressofs. */ +static void +rest_of_handle_addressof (tree decl, rtx insns) +{ + open_dump_file (DFI_addressof, decl); + + purge_addressof (insns); + if (optimize && purge_all_dead_edges (0)) + delete_unreachable_blocks (); + reg_scan (insns, max_reg_num (), 1); + + close_dump_file (DFI_addressof, print_rtl, insns); +} + +/* We may have potential sibling or tail recursion sites. Select one + (of possibly multiple) methods of performing the call. */ +static void +rest_of_handle_sibling_calls (rtx insns) +{ + rtx insn; + optimize_sibling_and_tail_recursive_calls (); + + /* Recompute the CFG as sibling optimization clobbers it randomly. */ + free_bb_for_insn (); + find_exception_handler_labels (); + rebuild_jump_labels (insns); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + + /* There is pass ordering problem - we must lower NOTE_INSN_PREDICTION + notes before simplifying cfg and we must do lowering after sibcall + that unhides parts of RTL chain and cleans up the CFG. + + Until sibcall is replaced by tree-level optimizer, lets just + sweep away the NOTE_INSN_PREDICTION notes that leaked out. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION) + delete_insn (insn); + + close_dump_file (DFI_sibling, print_rtl, get_insns ()); +} + +/* Perform jump bypassing and control flow optimizations. */ +static void +rest_of_handle_jump_bypass (tree decl, rtx insns) +{ + timevar_push (TV_BYPASS); + open_dump_file (DFI_bypass, decl); + + cleanup_cfg (CLEANUP_EXPENSIVE); + reg_scan (insns, max_reg_num (), 1); + + if (bypass_jumps (rtl_dump_file)) + { + rebuild_jump_labels (insns); + cleanup_cfg (CLEANUP_EXPENSIVE); + delete_trivially_dead_insns (insns, max_reg_num ()); + } + + close_dump_file (DFI_bypass, print_rtl_with_bb, insns); + timevar_pop (TV_BYPASS); + + ggc_collect (); + +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif +} + +/* Handle inlining of functions in rest_of_compilation. Return TRUE + if we must exit rest_of_compilation upon return. */ +static bool +rest_of_handle_inlining (tree decl) +{ + rtx insns; + int inlinable = 0; + tree parent; + const char *lose; + + /* If we are reconsidering an inline function at the end of + compilation, skip the stuff for making it inline. */ + if (cfun->rtl_inline_init) + return 0; + cfun->rtl_inline_init = 1; + + /* If this is nested inside an inlined external function, pretend + it was only declared. Since we cannot inline such functions, + generating code for this one is not only not necessary but will + confuse some debugging output writers. */ + for (parent = DECL_CONTEXT (current_function_decl); + parent != NULL_TREE; + parent = get_containing_scope (parent)) + if (TREE_CODE (parent) == FUNCTION_DECL + && DECL_INLINE (parent) && DECL_EXTERNAL (parent)) + { + DECL_INITIAL (decl) = 0; + return true; + } + else if (TYPE_P (parent)) + /* A function in a local class should be treated normally. */ + break; + + /* If requested, consider whether to make this function inline. */ + if ((DECL_INLINE (decl) && !flag_no_inline) + || flag_inline_functions) + { + timevar_push (TV_INTEGRATION); + lose = function_cannot_inline_p (decl); + timevar_pop (TV_INTEGRATION); + if (lose || ! optimize) + { + if (warn_inline && lose && DECL_INLINE (decl)) + { + char *msg = concat ("%J", lose, NULL); + warning (msg, decl); + free (msg); + } + DECL_ABSTRACT_ORIGIN (decl) = 0; + /* Don't really compile an extern inline function. + If we can't make it inline, pretend + it was only declared. */ + if (DECL_EXTERNAL (decl)) + { + DECL_INITIAL (decl) = 0; + return true; + } + } + else + inlinable = DECL_INLINE (decl) = 1; + } + + insns = get_insns (); + + /* Dump the rtl code if we are dumping rtl. */ + + if (open_dump_file (DFI_rtl, decl)) + { + if (DECL_SAVED_INSNS (decl) && DECL_SAVED_INSNS (decl)->saved_for_inline) + fprintf (rtl_dump_file, ";; (integrable)\n\n"); + close_dump_file (DFI_rtl, print_rtl, insns); + } + + /* Convert from NOTE_INSN_EH_REGION style notes, and do other + sorts of eh initialization. Delay this until after the + initial rtl dump so that we can see the original nesting. */ + convert_from_eh_region_ranges (); + + /* If function is inline, and we don't yet know whether to + compile it by itself, defer decision till end of compilation. + wrapup_global_declarations will (indirectly) call + rest_of_compilation again for those functions that need to + be output. Also defer those functions that we are supposed + to defer. */ + + if (inlinable + || (DECL_INLINE (decl) + /* Egad. This RTL deferral test conflicts with Fortran assumptions + for unreferenced symbols. See g77.f-torture/execute/980520-1.f. + But removing this line from the check breaks all languages that + use the call graph to output symbols. This hard-coded check is + the least invasive work-around. Nested functions need to be + deferred too. */ + && (flag_inline_functions + || strcmp (lang_hooks.name, "GNU F77") == 0 + || (cgraph_n_nodes > 0 && cgraph_node (decl)->origin)) + && ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl) + && ! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) + && ! flag_keep_inline_functions) + || DECL_EXTERNAL (decl)))) + DECL_DEFER_OUTPUT (decl) = 1; + + if (DECL_INLINE (decl)) + /* DWARF wants separate debugging info for abstract and + concrete instances of all inline functions, including those + declared inline but not inlined, and those inlined even + though they weren't declared inline. Conveniently, that's + what DECL_INLINE means at this point. */ + (*debug_hooks->deferred_inline_function) (decl); + + if (DECL_DEFER_OUTPUT (decl)) + { + /* If -Wreturn-type, we have to do a bit of compilation. We just + want to call cleanup the cfg to figure out whether or not we can + fall off the end of the function; we do the minimum amount of + work necessary to make that safe. */ + if (warn_return_type) + { + int saved_optimize = optimize; + + optimize = 0; + rebuild_jump_labels (insns); + find_exception_handler_labels (); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + cleanup_cfg (CLEANUP_PRE_SIBCALL | CLEANUP_PRE_LOOP); + optimize = saved_optimize; + + /* CFG is no longer maintained up-to-date. */ + free_bb_for_insn (); + } + + set_nothrow_function_flags (); + if (current_function_nothrow) + /* Now we know that this can't throw; set the flag for the benefit + of other functions later in this translation unit. */ + TREE_NOTHROW (current_function_decl) = 1; + + timevar_push (TV_INTEGRATION); + save_for_inline (decl); + timevar_pop (TV_INTEGRATION); + DECL_SAVED_INSNS (decl)->inlinable = inlinable; + return true; + } + + /* If specified extern inline but we aren't inlining it, we are + done. This goes for anything that gets here with DECL_EXTERNAL + set, not just things with DECL_INLINE. */ + return (bool) DECL_EXTERNAL (decl); +} + +/* Try to identify useless null pointer tests and delete them. */ +static void +rest_of_handle_null_pointer (tree decl, rtx insns) +{ + open_dump_file (DFI_null, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + + if (delete_null_pointer_checks (insns)) + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + + close_dump_file (DFI_null, print_rtl_with_bb, insns); +} + +/* Try combining insns through substitution. */ +static void +rest_of_handle_combine (tree decl, rtx insns) +{ + int rebuild_jump_labels_after_combine = 0; + + timevar_push (TV_COMBINE); + open_dump_file (DFI_combine, decl); + + rebuild_jump_labels_after_combine + = combine_instructions (insns, max_reg_num ()); + + /* Combining insns may have turned an indirect jump into a + direct jump. Rebuild the JUMP_LABEL fields of jumping + instructions. */ + if (rebuild_jump_labels_after_combine) + { + timevar_push (TV_JUMP); + rebuild_jump_labels (insns); + timevar_pop (TV_JUMP); + + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); + } + + close_dump_file (DFI_combine, print_rtl_with_bb, insns); + timevar_pop (TV_COMBINE); + + ggc_collect (); +} + +/* Perform life analysis. */ +static void +rest_of_handle_life (tree decl, rtx insns) +{ + open_dump_file (DFI_life, decl); + regclass_init (); + +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif + life_analysis (insns, rtl_dump_file, PROP_FINAL); + if (optimize) + cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_UPDATE_LIFE + | CLEANUP_LOG_LINKS + | (flag_thread_jumps ? CLEANUP_THREADING : 0)); + timevar_pop (TV_FLOW); + + if (warn_uninitialized) + { + uninitialized_vars_warning (DECL_INITIAL (decl)); + if (extra_warnings) + setjmp_args_warning (); + } + + if (optimize) + { + if (!flag_new_regalloc && initialize_uninitialized_subregs ()) + { + /* Insns were inserted, and possibly pseudos created, so + things might look a bit different. */ + insns = get_insns (); + allocate_reg_life_data (); + update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES, + PROP_LOG_LINKS | PROP_REG_INFO | PROP_DEATH_NOTES); + } + } + + no_new_pseudos = 1; + + close_dump_file (DFI_life, print_rtl_with_bb, insns); + + ggc_collect (); +} + +/* Perform common subexpression elimination. Nonzero value from + `cse_main' means that jumps were simplified and some code may now + be unreachable, so do jump optimization again. */ +static void +rest_of_handle_cse (tree decl, rtx insns) +{ + int tem; + + open_dump_file (DFI_cse, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + timevar_push (TV_CSE); + + reg_scan (insns, max_reg_num (), 1); + + tem = cse_main (insns, max_reg_num (), 0, rtl_dump_file); + if (tem) + rebuild_jump_labels (insns); + if (purge_all_dead_edges (0)) + delete_unreachable_blocks (); + + delete_trivially_dead_insns (insns, max_reg_num ()); + + /* If we are not running more CSE passes, then we are no longer + expecting CSE to be run. But always rerun it in a cheap mode. */ + cse_not_expected = !flag_rerun_cse_after_loop && !flag_gcse; + + if (tem || optimize > 1) + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + /* Try to identify useless null pointer tests and delete them. */ + if (flag_delete_null_pointer_checks) + { + timevar_push (TV_JUMP); + + if (delete_null_pointer_checks (insns)) + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + timevar_pop (TV_JUMP); + } + + /* The second pass of jump optimization is likely to have + removed a bunch more instructions. */ + renumber_insns (rtl_dump_file); + + timevar_pop (TV_CSE); + close_dump_file (DFI_cse, print_rtl_with_bb, insns); +} + +/* Run second CSE pass after loop optimizations. */ +static void +rest_of_handle_cse2 (tree decl, rtx insns) +{ + int tem; + + timevar_push (TV_CSE2); + open_dump_file (DFI_cse2, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + /* CFG is no longer maintained up-to-date. */ + tem = cse_main (insns, max_reg_num (), 1, rtl_dump_file); + + /* Run a pass to eliminate duplicated assignments to condition code + registers. We have to run this after bypass_jumps, because it + makes it harder for that pass to determine whether a jump can be + bypassed safely. */ + cse_condition_code_reg (); + + purge_all_dead_edges (0); + delete_trivially_dead_insns (insns, max_reg_num ()); + + if (tem) + { + timevar_push (TV_JUMP); + rebuild_jump_labels (insns); + cleanup_cfg (CLEANUP_EXPENSIVE); + timevar_pop (TV_JUMP); + } + reg_scan (insns, max_reg_num (), 0); + close_dump_file (DFI_cse2, print_rtl_with_bb, insns); + ggc_collect (); + timevar_pop (TV_CSE2); +} + +/* Perform global cse. */ +static void +rest_of_handle_gcse (tree decl, rtx insns) +{ + int save_csb, save_cfj; + int tem2 = 0, tem; + + timevar_push (TV_GCSE); + open_dump_file (DFI_gcse, decl); + + tem = gcse_main (insns, rtl_dump_file); + rebuild_jump_labels (insns); + delete_trivially_dead_insns (insns, max_reg_num ()); + + save_csb = flag_cse_skip_blocks; + save_cfj = flag_cse_follow_jumps; + flag_cse_skip_blocks = flag_cse_follow_jumps = 0; + + /* Instantiate any remaining CONSTANT_P_RTX nodes. */ + if (current_function_calls_constant_p) + purge_builtin_constant_p (); + + /* If -fexpensive-optimizations, re-run CSE to clean up things done + by gcse. */ + if (flag_expensive_optimizations) + { + timevar_push (TV_CSE); + reg_scan (insns, max_reg_num (), 1); + tem2 = cse_main (insns, max_reg_num (), 0, rtl_dump_file); + purge_all_dead_edges (0); + delete_trivially_dead_insns (insns, max_reg_num ()); + timevar_pop (TV_CSE); + cse_not_expected = !flag_rerun_cse_after_loop; + } + + /* If gcse or cse altered any jumps, rerun jump optimizations to clean + things up. Then possibly re-run CSE again. */ + while (tem || tem2) + { + tem = tem2 = 0; + timevar_push (TV_JUMP); + rebuild_jump_labels (insns); + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + timevar_pop (TV_JUMP); + + if (flag_expensive_optimizations) + { + timevar_push (TV_CSE); + reg_scan (insns, max_reg_num (), 1); + tem2 = cse_main (insns, max_reg_num (), 0, rtl_dump_file); + purge_all_dead_edges (0); + delete_trivially_dead_insns (insns, max_reg_num ()); + timevar_pop (TV_CSE); + } + } + + close_dump_file (DFI_gcse, print_rtl_with_bb, insns); + timevar_pop (TV_GCSE); + + ggc_collect (); + flag_cse_skip_blocks = save_csb; + flag_cse_follow_jumps = save_cfj; +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif +} + +/* Move constant computations out of loops. */ +static void +rest_of_handle_loop_optimize (tree decl, rtx insns) +{ + int do_unroll, do_prefetch; + + timevar_push (TV_LOOP); + delete_dead_jumptables (); + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + open_dump_file (DFI_loop, decl); + + /* CFG is no longer maintained up-to-date. */ + free_bb_for_insn (); + + if (flag_unroll_loops) + do_unroll = LOOP_AUTO_UNROLL; /* Having two unrollers is useless. */ + else + do_unroll = flag_old_unroll_loops ? LOOP_UNROLL : LOOP_AUTO_UNROLL; + do_prefetch = flag_prefetch_loop_arrays ? LOOP_PREFETCH : 0; + + if (flag_rerun_loop_opt) + { + cleanup_barriers (); + + /* We only want to perform unrolling once. */ + loop_optimize (insns, rtl_dump_file, do_unroll); + do_unroll = 0; + + /* The first call to loop_optimize makes some instructions + trivially dead. We delete those instructions now in the + hope that doing so will make the heuristics in loop work + better and possibly speed up compilation. */ + delete_trivially_dead_insns (insns, max_reg_num ()); + + /* The regscan pass is currently necessary as the alias + analysis code depends on this information. */ + reg_scan (insns, max_reg_num (), 1); + } + cleanup_barriers (); + loop_optimize (insns, rtl_dump_file, do_unroll | LOOP_BCT | do_prefetch); + + /* Loop can create trivially dead instructions. */ + delete_trivially_dead_insns (insns, max_reg_num ()); + close_dump_file (DFI_loop, print_rtl, insns); + timevar_pop (TV_LOOP); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + + ggc_collect (); +} + +/* Perform loop optimizations. It might be better to do them a bit + sooner, but we want the profile feedback to work more + efficiently. */ +static void +rest_of_handle_loop2 (tree decl, rtx insns) +{ + struct loops *loops; + timevar_push (TV_LOOP); + open_dump_file (DFI_loop2, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + + loops = loop_optimizer_init (rtl_dump_file); + + if (loops) + { + /* The optimizations: */ + if (flag_unswitch_loops) + unswitch_loops (loops); + + if (flag_peel_loops || flag_unroll_loops) + unroll_and_peel_loops (loops, + (flag_peel_loops ? UAP_PEEL : 0) | + (flag_unroll_loops ? UAP_UNROLL : 0) | + (flag_unroll_all_loops ? UAP_UNROLL_ALL : 0)); + + loop_optimizer_finalize (loops, rtl_dump_file); + } + + cleanup_cfg (CLEANUP_EXPENSIVE); + delete_trivially_dead_insns (insns, max_reg_num ()); + reg_scan (insns, max_reg_num (), 0); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + close_dump_file (DFI_loop2, print_rtl_with_bb, get_insns ()); + timevar_pop (TV_LOOP); + ggc_collect (); +} + +/* This is called from finish_function (within langhooks.parse_file) + after each top-level definition is parsed. + It is supposed to compile that function or variable + and output the assembler code for it. + After we return, the tree storage is freed. */ + +void +rest_of_compilation (tree decl) +{ + rtx insns; + + timevar_push (TV_REST_OF_COMPILATION); + + /* Register rtl specific functions for cfg. */ + rtl_register_cfg_hooks (); + + /* Now that we're out of the frontend, we shouldn't have any more + CONCATs anywhere. */ + generating_concat_p = 0; + + /* When processing delayed functions, prepare_function_start() won't + have been run to re-initialize it. */ + cse_not_expected = ! optimize; + + /* First, make sure that NOTE_BLOCK is set correctly for each + NOTE_INSN_BLOCK_BEG/NOTE_INSN_BLOCK_END note. */ + if (!cfun->x_whole_function_mode_p) + identify_blocks (); + + /* In function-at-a-time mode, we do not attempt to keep the BLOCK + tree in sensible shape. So, we just recalculate it here. */ + if (cfun->x_whole_function_mode_p) + reorder_blocks (); + + init_flow (); + + if (rest_of_handle_inlining (decl)) + goto exit_rest_of_compilation; + + /* If we're emitting a nested function, make sure its parent gets + emitted as well. Doing otherwise confuses debug info. */ + { + tree parent; + for (parent = DECL_CONTEXT (current_function_decl); + parent != NULL_TREE; + parent = get_containing_scope (parent)) + if (TREE_CODE (parent) == FUNCTION_DECL) + TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (parent)) = 1; + } + + /* We are now committed to emitting code for this function. Do any + preparation, such as emitting abstract debug info for the inline + before it gets mangled by optimization. */ + if (cgraph_function_possibly_inlined_p (decl)) + (*debug_hooks->outlining_inline_function) (decl); + + /* Remove any notes we don't need. That will make iterating + over the instruction sequence faster, and allow the garbage + collector to reclaim the memory used by the notes. */ + remove_unnecessary_notes (); + reorder_blocks (); + + ggc_collect (); + + /* Initialize some variables used by the optimizers. */ + init_function_for_compilation (); + + if (! DECL_DEFER_OUTPUT (decl)) + TREE_ASM_WRITTEN (decl) = 1; + + /* Now that integrate will no longer see our rtl, we need not + distinguish between the return value of this function and the + return value of called functions. Also, we can remove all SETs + of subregs of hard registers; they are only here because of + integrate. Also, we can now initialize pseudos intended to + carry magic hard reg data throughout the function. */ + rtx_equal_function_value_matters = 0; + purge_hard_subreg_sets (get_insns ()); + + /* Early return if there were errors. We can run afoul of our + consistency checks, and there's not really much point in fixing them. + Don't return yet if -Wreturn-type; we need to do cleanup_cfg. */ + if (((rtl_dump_and_exit || flag_syntax_only) && !warn_return_type) + || errorcount || sorrycount) + goto exit_rest_of_compilation; + + timevar_push (TV_JUMP); + open_dump_file (DFI_sibling, decl); + insns = get_insns (); + rebuild_jump_labels (insns); + find_exception_handler_labels (); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + + delete_unreachable_blocks (); + + /* Turn NOTE_INSN_PREDICTIONs into branch predictions. */ + if (flag_guess_branch_prob) + { + timevar_push (TV_BRANCH_PROB); + note_prediction_to_br_prob (); + timevar_pop (TV_BRANCH_PROB); + } + + if (flag_optimize_sibling_calls) + rest_of_handle_sibling_calls (insns); + + /* We have to issue these warnings now already, because CFG cleanups + further down may destroy the required information. However, this + must be done after the sibcall optimization pass because the barrier + emitted for noreturn calls that are candidate for the optimization + is folded into the CALL_PLACEHOLDER until after this pass, so the + CFG is inaccurate. */ + check_function_return_warnings (); + + timevar_pop (TV_JUMP); + + insn_locators_initialize (); + /* Complete generation of exception handling code. */ + if (doing_eh (0)) + { + timevar_push (TV_JUMP); + open_dump_file (DFI_eh, decl); + + finish_eh_generation (); + + close_dump_file (DFI_eh, print_rtl, get_insns ()); + timevar_pop (TV_JUMP); + } + + /* Delay emitting hard_reg_initial_value sets until after EH landing pad + generation, which might create new sets. */ + emit_initial_value_sets (); + +#ifdef FINALIZE_PIC + /* If we are doing position-independent code generation, now + is the time to output special prologues and epilogues. + We do not want to do this earlier, because it just clutters + up inline functions with meaningless insns. */ + if (flag_pic) + FINALIZE_PIC; +#endif + + insns = get_insns (); + + /* Copy any shared structure that should not be shared. */ + unshare_all_rtl (current_function_decl, insns); + +#ifdef SETJMP_VIA_SAVE_AREA + /* This must be performed before virtual register instantiation. + Please be aware the everything in the compiler that can look + at the RTL up to this point must understand that REG_SAVE_AREA + is just like a use of the REG contained inside. */ + if (current_function_calls_alloca) + optimize_save_area_alloca (insns); +#endif + + /* Instantiate all virtual registers. */ + instantiate_virtual_regs (current_function_decl, insns); + + open_dump_file (DFI_jump, decl); + + /* Always do one jump optimization pass to ensure that JUMP_LABEL fields + are initialized and to compute whether control can drop off the end + of the function. */ + + timevar_push (TV_JUMP); + /* Turn NOTE_INSN_EXPECTED_VALUE into REG_BR_PROB. Do this + before jump optimization switches branch directions. */ + if (flag_guess_branch_prob) + expected_value_to_br_prob (); + + reg_scan (insns, max_reg_num (), 0); + rebuild_jump_labels (insns); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + delete_trivially_dead_insns (insns, max_reg_num ()); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP + | (flag_thread_jumps ? CLEANUP_THREADING : 0)); + + if (optimize) + { + free_bb_for_insn (); + copy_loop_headers (insns); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + } + purge_line_number_notes (insns); + + timevar_pop (TV_JUMP); + close_dump_file (DFI_jump, print_rtl, insns); + + /* Now is when we stop if -fsyntax-only and -Wreturn-type. */ + if (rtl_dump_and_exit || flag_syntax_only || DECL_DEFER_OUTPUT (decl)) + goto exit_rest_of_compilation; + + timevar_push (TV_JUMP); + + if (optimize) + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + + if (flag_delete_null_pointer_checks) + rest_of_handle_null_pointer (decl, insns); + + /* Jump optimization, and the removal of NULL pointer checks, may + have reduced the number of instructions substantially. CSE, and + future passes, allocate arrays whose dimensions involve the + maximum instruction UID, so if we can reduce the maximum UID + we'll save big on memory. */ + renumber_insns (rtl_dump_file); + timevar_pop (TV_JUMP); + + close_dump_file (DFI_jump, print_rtl_with_bb, insns); + + ggc_collect (); + + if (optimize > 0) + rest_of_handle_cse (decl, insns); + + rest_of_handle_addressof (decl, insns); + + ggc_collect (); + + if (optimize > 0) + { + if (flag_gcse) + rest_of_handle_gcse (decl, insns); + + if (flag_loop_optimize) + rest_of_handle_loop_optimize (decl, insns); + + if (flag_gcse) + rest_of_handle_jump_bypass (decl, insns); + } + + timevar_push (TV_FLOW); + + rest_of_handle_cfg (decl, insns); + + if (optimize > 0 + || profile_arc_flag || flag_test_coverage || flag_branch_probabilities) + { + rest_of_handle_branch_prob (decl, insns); + + if (flag_branch_probabilities + && flag_profile_values + && flag_value_profile_transformations) + rest_of_handle_value_profile_transformations (decl, insns); + + /* Remove the death notes created for vpt. */ + if (flag_profile_values) + count_or_remove_death_notes (NULL, 1); + } + + if (optimize > 0) + rest_of_handle_if_conversion (decl, insns); + + if (flag_tracer) + rest_of_handle_tracer (decl, insns); + + if (optimize > 0 + && (flag_unswitch_loops + || flag_peel_loops + || flag_unroll_loops)) + rest_of_handle_loop2 (decl, insns); + + if (flag_web) + rest_of_handle_web (decl, insns); + + if (flag_rerun_cse_after_loop) + rest_of_handle_cse2 (decl, insns); + + cse_not_expected = 1; + + rest_of_handle_life (decl, insns); + + if (optimize > 0) + rest_of_handle_combine (decl, insns); + + if (flag_if_conversion) + rest_of_handle_if_after_combine (decl, insns); + + if (optimize > 0 && (flag_regmove || flag_expensive_optimizations)) + rest_of_handle_regmove (decl, insns); + + /* Do unconditional splitting before register allocation to allow machine + description to add extra information not needed previously. */ + split_all_insns (1); + +#ifdef OPTIMIZE_MODE_SWITCHING + timevar_push (TV_MODE_SWITCH); + + no_new_pseudos = 0; + optimize_mode_switching (NULL); + no_new_pseudos = 1; + + timevar_pop (TV_MODE_SWITCH); +#endif + + /* Any of the several passes since flow1 will have munged register + lifetime data a bit. We need it to be up to date for scheduling + (see handling of reg_known_equiv in init_alias_analysis). */ + recompute_reg_usage (insns, !optimize_size); + +#ifdef INSN_SCHEDULING + rest_of_handle_sched (decl, insns); +#endif + + /* Determine if the current function is a leaf before running reload + since this can impact optimizations done by the prologue and + epilogue thus changing register elimination offsets. */ + current_function_is_leaf = leaf_function_p (); + + timevar_push (TV_LOCAL_ALLOC); + open_dump_file (DFI_lreg, decl); + + if (flag_new_regalloc) + { + if (rest_of_handle_new_regalloc (decl, insns)) + goto exit_rest_of_compilation; + } + else + { + if (rest_of_handle_old_regalloc (decl, insns)) + goto exit_rest_of_compilation; + } + + ggc_collect (); + + open_dump_file (DFI_postreload, decl); + + /* Do a very simple CSE pass over just the hard registers. */ + if (optimize > 0) + { + timevar_push (TV_RELOAD_CSE_REGS); + reload_cse_regs (insns); + /* reload_cse_regs can eliminate potentially-trapping MEMs. + Remove any EH edges associated with them. */ + if (flag_non_call_exceptions) + purge_all_dead_edges (0); + timevar_pop (TV_RELOAD_CSE_REGS); + } + + close_dump_file (DFI_postreload, print_rtl_with_bb, insns); + + /* Re-create the death notes which were deleted during reload. */ + timevar_push (TV_FLOW2); + open_dump_file (DFI_flow2, decl); + +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif + + /* If optimizing, then go ahead and split insns now. */ +#ifndef STACK_REGS + if (optimize > 0) +#endif + split_all_insns (0); + + if (flag_branch_target_load_optimize) + { + open_dump_file (DFI_branch_target_load, decl); + + branch_target_load_optimize (insns, false); + + close_dump_file (DFI_branch_target_load, print_rtl_with_bb, insns); + + ggc_collect (); + } + + if (optimize) + cleanup_cfg (CLEANUP_EXPENSIVE); + + /* On some machines, the prologue and epilogue code, or parts thereof, + can be represented as RTL. Doing so lets us schedule insns between + it and the rest of the code and also allows delayed branch + scheduling to operate in the epilogue. */ + thread_prologue_and_epilogue_insns (insns); + epilogue_completed = 1; + + if (optimize) + { + life_analysis (insns, rtl_dump_file, PROP_POSTRELOAD); + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE + | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0)); + + /* This is kind of a heuristic. We need to run combine_stack_adjustments + even for machines with possibly nonzero RETURN_POPS_ARGS + and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having + push instructions will have popping returns. */ +#ifndef PUSH_ROUNDING + if (!ACCUMULATE_OUTGOING_ARGS) +#endif + combine_stack_adjustments (); + + ggc_collect (); + } + + flow2_completed = 1; + + close_dump_file (DFI_flow2, print_rtl_with_bb, insns); + timevar_pop (TV_FLOW2); + +#ifdef HAVE_peephole2 + if (optimize > 0 && flag_peephole2) + { + timevar_push (TV_PEEPHOLE2); + open_dump_file (DFI_peephole2, decl); + + peephole2_optimize (rtl_dump_file); + + close_dump_file (DFI_peephole2, print_rtl_with_bb, insns); + timevar_pop (TV_PEEPHOLE2); + } +#endif + + open_dump_file (DFI_ce3, decl); + if (optimize) + /* Last attempt to optimize CFG, as scheduling, peepholing and insn + splitting possibly introduced more crossjumping opportunities. */ + cleanup_cfg (CLEANUP_EXPENSIVE + | CLEANUP_UPDATE_LIFE + | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0)); + if (flag_if_conversion2) + { + timevar_push (TV_IFCVT2); + + if_convert (1); + + timevar_pop (TV_IFCVT2); + } + close_dump_file (DFI_ce3, print_rtl_with_bb, insns); + + if (optimize > 0) + { + if (flag_rename_registers || flag_cprop_registers) + rest_of_handle_regrename (decl, insns); + + rest_of_handle_reorder_blocks (decl, insns); + } + + if (flag_branch_target_load_optimize2) + { + /* Leave this a warning for now so that it is possible to experiment + with running this pass twice. In 3.6, we should either make this + an error, or use separate dump files. */ + if (flag_branch_target_load_optimize) + warning ("branch target register load optimization is not intended " + "to be run twice"); + + open_dump_file (DFI_branch_target_load, decl); + + branch_target_load_optimize (insns, true); + + close_dump_file (DFI_branch_target_load, print_rtl_with_bb, insns); + + ggc_collect (); + } + +#ifdef INSN_SCHEDULING + if (optimize > 0 && flag_schedule_insns_after_reload) + rest_of_handle_sched2 (decl, insns); +#endif + +#ifdef LEAF_REGISTERS + current_function_uses_only_leaf_regs + = optimize > 0 && only_leaf_regs_used () && leaf_function_p (); +#endif + +#ifdef STACK_REGS + rest_of_handle_stack_regs (decl, insns); +#endif + + compute_alignments (); + + /* CFG is no longer maintained up-to-date. */ + free_bb_for_insn (); + + if (targetm.machine_dependent_reorg != 0) + rest_of_handle_machine_reorg (decl, insns); + + purge_line_number_notes (insns); + cleanup_barriers (); + +#ifdef DELAY_SLOTS + if (optimize > 0 && flag_delayed_branch) + rest_of_handle_delay_slots (decl, insns); +#endif + +#if defined (HAVE_ATTR_length) && !defined (STACK_REGS) + timevar_push (TV_SHORTEN_BRANCH); + split_all_insns_noflow (); + timevar_pop (TV_SHORTEN_BRANCH); +#endif + + convert_to_eh_region_ranges (); + + /* Shorten branches. */ + timevar_push (TV_SHORTEN_BRANCH); + shorten_branches (get_insns ()); + timevar_pop (TV_SHORTEN_BRANCH); + + set_nothrow_function_flags (); + if (current_function_nothrow) + /* Now we know that this can't throw; set the flag for the benefit + of other functions later in this translation unit. */ + TREE_NOTHROW (current_function_decl) = 1; + + rest_of_handle_final (decl, insns); + + /* Write DBX symbols if requested. */ + + /* Note that for those inline functions where we don't initially + know for certain that we will be generating an out-of-line copy, + the first invocation of this routine (rest_of_compilation) will + skip over this code by doing a `goto exit_rest_of_compilation;'. + Later on, wrapup_global_declarations will (indirectly) call + rest_of_compilation again for those inline functions that need + to have out-of-line copies generated. During that call, we + *will* be routed past here. */ + + timevar_push (TV_SYMOUT); + (*debug_hooks->function_decl) (decl); + timevar_pop (TV_SYMOUT); + + exit_rest_of_compilation: + + coverage_end_function (); + + /* In case the function was not output, + don't leave any temporary anonymous types + queued up for sdb output. */ +#ifdef SDB_DEBUGGING_INFO + if (write_symbols == SDB_DEBUG) + sdbout_types (NULL_TREE); +#endif + + reload_completed = 0; + epilogue_completed = 0; + flow2_completed = 0; + no_new_pseudos = 0; + + timevar_push (TV_FINAL); + + /* Clear out the insn_length contents now that they are no + longer valid. */ + init_insn_lengths (); + + /* Show no temporary slots allocated. */ + init_temp_slots (); + + free_basic_block_vars (0); + free_bb_for_insn (); + + timevar_pop (TV_FINAL); + + if ((*targetm.binds_local_p) (current_function_decl)) + { + int pref = cfun->preferred_stack_boundary; + if (cfun->stack_alignment_needed > cfun->preferred_stack_boundary) + pref = cfun->stack_alignment_needed; + cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary + = pref; + } + + /* Make sure volatile mem refs aren't considered valid operands for + arithmetic insns. We must call this here if this is a nested inline + function, since the above code leaves us in the init_recog state + (from final.c), and the function context push/pop code does not + save/restore volatile_ok. + + ??? Maybe it isn't necessary for expand_start_function to call this + anymore if we do it here? */ + + init_recog_no_volatile (); + + /* We're done with this function. Free up memory if we can. */ + free_after_parsing (cfun); + if (! DECL_DEFER_OUTPUT (decl)) + { + free_after_compilation (cfun); + DECL_SAVED_INSNS (decl) = 0; + } + cfun = 0; + + ggc_collect (); + + timevar_pop (TV_REST_OF_COMPILATION); +} + +/* Display help for target options. */ +void +display_target_options (void) +{ + int undoc, i; + static bool displayed = false; + + /* Avoid double printing for --help --target-help. */ + if (displayed) + return; + + displayed = true; + + if (ARRAY_SIZE (target_switches) > 1 +#ifdef TARGET_OPTIONS + || ARRAY_SIZE (target_options) > 1 +#endif + ) + { + int doc = 0; + + undoc = 0; + + printf (_("\nTarget specific options:\n")); + + for (i = ARRAY_SIZE (target_switches); i--;) + { + const char *option = target_switches[i].name; + const char *description = target_switches[i].description; + + if (option == NULL || *option == 0) + continue; + else if (description == NULL) + { + undoc = 1; + + if (extra_warnings) + printf (_(" -m%-23s [undocumented]\n"), option); + } + else if (*description != 0) + doc += printf (" -m%-23s %s\n", option, _(description)); + } + +#ifdef TARGET_OPTIONS + for (i = ARRAY_SIZE (target_options); i--;) + { + const char *option = target_options[i].prefix; + const char *description = target_options[i].description; + + if (option == NULL || *option == 0) + continue; + else if (description == NULL) + { + undoc = 1; + + if (extra_warnings) + printf (_(" -m%-23s [undocumented]\n"), option); + } + else if (*description != 0) + doc += printf (" -m%-23s %s\n", option, _(description)); + } +#endif + if (undoc) + { + if (doc) + printf (_("\nThere are undocumented target specific options as well.\n")); + else + printf (_(" They exist, but they are not documented.\n")); + } + } } /* Parse a -d... command line switch. */ @@ -1103,11 +3773,15 @@ compile_file (void) void decode_d_option (const char *arg) { - int c; + int i, c, matched; while (*arg) switch (c = *arg++) { + case 'a': + for (i = 0; i < (int) DFI_MAX; ++i) + dump_file[i].enabled = 1; + break; case 'A': flag_debug_asm = 1; break; @@ -1134,10 +3808,17 @@ decode_d_option (const char *arg) setup_core_dumping(); break; - case 'a': default: - if (!enable_rtl_dump_file (c)) - warning (0, "unrecognized gcc debugging option: %c", c); + matched = 0; + for (i = 0; i < (int) DFI_MAX; ++i) + if (c == dump_file[i].debug_switch) + { + dump_file[i].enabled = 1; + matched = 1; + } + + if (! matched) + warning ("unrecognized gcc debugging option: %c", c); break; } } @@ -1145,9 +3826,63 @@ decode_d_option (const char *arg) /* Indexed by enum debug_info_type. */ const char *const debug_type_names[] = { - "none", "stabs", "coff", "dwarf-2", "xcoff", "vms" + "none", "stabs", "coff", "dwarf-1", "dwarf-2", "xcoff", "vms" }; +/* Decode -m switches. */ +/* Decode the switch -mNAME. */ + +void +set_target_switch (const char *name) +{ + size_t j; + int valid_target_option = 0; + + for (j = 0; j < ARRAY_SIZE (target_switches); j++) + if (!strcmp (target_switches[j].name, name)) + { + if (target_switches[j].value < 0) + target_flags &= ~-target_switches[j].value; + else + target_flags |= target_switches[j].value; + if (name[0] != 0) + { + if (target_switches[j].value < 0) + target_flags_explicit |= -target_switches[j].value; + else + target_flags_explicit |= target_switches[j].value; + } + valid_target_option = 1; + } + +#ifdef TARGET_OPTIONS + if (!valid_target_option) + for (j = 0; j < ARRAY_SIZE (target_options); j++) + { + int len = strlen (target_options[j].prefix); + if (target_options[j].value) + { + if (!strcmp (target_options[j].prefix, name)) + { + *target_options[j].variable = target_options[j].value; + valid_target_option = 1; + } + } + else + { + if (!strncmp (target_options[j].prefix, name, len)) + { + *target_options[j].variable = name + len; + valid_target_option = 1; + } + } + } +#endif + + if (!valid_target_option) + error ("invalid option `%s'", name); +} + /* Print version information to FILE. Each line begins with INDENT (for the case where FILE is the assembler output file). */ @@ -1155,25 +3890,19 @@ const char *const debug_type_names[] = void print_version (FILE *file, const char *indent) { - static const char fmt1[] = -#ifdef __GNUC__ - N_("%s%s%s version %s (%s)\n%s\tcompiled by GNU C version %s.\n") -#else - N_("%s%s%s version %s (%s) compiled by CC.\n") -#endif - ; - static const char fmt2[] = - N_("%s%sGGC heuristics: --param ggc-min-expand=%d --param ggc-min-heapsize=%d\n"); #ifndef __VERSION__ #define __VERSION__ "[?]" #endif - fprintf (file, - file == stderr ? _(fmt1) : fmt1, - indent, *indent != 0 ? " " : "", + fnotice (file, +#ifdef __GNUC__ + "%s%s%s version %s (%s)\n%s\tcompiled by GNU C version %s.\n" +#else + "%s%s%s version %s (%s) compiled by CC.\n" +#endif + , indent, *indent != 0 ? " " : "", lang_hooks.name, version_string, TARGET_NAME, indent, __VERSION__); - fprintf (file, - file == stderr ? _(fmt2) : fmt2, + fnotice (file, "%s%sGGC heuristics: --param ggc-min-expand=%d --param ggc-min-heapsize=%d\n", indent, *indent != 0 ? " " : "", PARAM_VALUE (GGC_MIN_EXPAND), PARAM_VALUE (GGC_MIN_HEAPSIZE)); } @@ -1256,11 +3985,33 @@ print_switch_values (FILE *file, int pos, int max, pos = print_single_switch (file, 0, max, indent, *indent ? " " : "", term, _("options enabled: "), ""); - for (j = 0; j < cl_options_count; j++) - if ((cl_options[j].flags & CL_REPORT) - && option_enabled (j) > 0) + for (j = 0; j < ARRAY_SIZE (f_options); j++) + if (*f_options[j].variable == f_options[j].on_value) pos = print_single_switch (file, pos, max, indent, sep, term, - "", cl_options[j].opt_text); + "-f", f_options[j].string); + + /* Print target specific options. */ + + for (j = 0; j < ARRAY_SIZE (target_switches); j++) + if (target_switches[j].name[0] != '\0' + && target_switches[j].value > 0 + && ((target_switches[j].value & target_flags) + == target_switches[j].value)) + { + pos = print_single_switch (file, pos, max, indent, sep, term, + "-m", target_switches[j].name); + } + +#ifdef TARGET_OPTIONS + for (j = 0; j < ARRAY_SIZE (target_options); j++) + if (*target_options[j].variable != NULL) + { + char prefix[256]; + sprintf (prefix, "-m%s", target_options[j].prefix); + pos = print_single_switch (file, pos, max, indent, sep, term, + prefix, *target_options[j].variable); + } +#endif fprintf (file, "%s", term); } @@ -1279,7 +4030,7 @@ init_asm_output (const char *name) if (asm_file_name == 0) { int len = strlen (dump_base_name); - char *dumpname = XNEWVEC (char, len + 6); + char *dumpname = xmalloc (len + 6); memcpy (dumpname, dump_base_name, len + 1); strip_off_ending (dumpname, len); strcat (dumpname, ".s"); @@ -1288,11 +4039,16 @@ init_asm_output (const char *name) if (!strcmp (asm_file_name, "-")) asm_out_file = stdout; else - asm_out_file = fopen (asm_file_name, "w+b"); + asm_out_file = fopen (asm_file_name, "w+"); if (asm_out_file == 0) - fatal_error ("can%'t open %s for writing: %m", asm_file_name); + fatal_error ("can't open %s for writing: %m", asm_file_name); } +#ifdef IO_BUFFER_SIZE + setvbuf (asm_out_file, xmalloc (IO_BUFFER_SIZE), + _IOFBF, IO_BUFFER_SIZE); +#endif + if (!flag_syntax_only) { targetm.asm_out.file_start (); @@ -1312,21 +4068,6 @@ init_asm_output (const char *name) } } -/* Return true if the state of option OPTION should be stored in PCH files - and checked by default_pch_valid_p. Store the option's current state - in STATE if so. */ - -static inline bool -option_affects_pch_p (int option, struct cl_option_state *state) -{ - if ((cl_options[option].flags & CL_TARGET) == 0) - return false; - if (cl_options[option].flag_var == &target_flags) - if (targetm.check_pch_target_flags) - return false; - return get_option_state (option, state); -} - /* Default version of get_pch_validity. By default, every flag difference is fatal; that will be mostly right for most targets, but completely right for very few. */ @@ -1334,58 +4075,51 @@ option_affects_pch_p (int option, struct cl_option_state *state) void * default_get_pch_validity (size_t *len) { - struct cl_option_state state; +#ifdef TARGET_OPTIONS size_t i; +#endif char *result, *r; - *len = 2; - if (targetm.check_pch_target_flags) - *len += sizeof (target_flags); - for (i = 0; i < cl_options_count; i++) - if (option_affects_pch_p (i, &state)) - *len += state.size; + *len = sizeof (target_flags) + 2; +#ifdef TARGET_OPTIONS + for (i = 0; i < ARRAY_SIZE (target_options); i++) + { + *len += 1; + if (*target_options[i].variable) + *len += strlen (*target_options[i].variable); + } +#endif - result = r = XNEWVEC (char, *len); + result = r = xmalloc (*len); r[0] = flag_pic; r[1] = flag_pie; r += 2; - if (targetm.check_pch_target_flags) + memcpy (r, &target_flags, sizeof (target_flags)); + r += sizeof (target_flags); + +#ifdef TARGET_OPTIONS + for (i = 0; i < ARRAY_SIZE (target_options); i++) { - memcpy (r, &target_flags, sizeof (target_flags)); - r += sizeof (target_flags); + const char *str = *target_options[i].variable; + size_t l; + if (! str) + str = ""; + l = strlen (str) + 1; + memcpy (r, str, l); + r += l; } - - for (i = 0; i < cl_options_count; i++) - if (option_affects_pch_p (i, &state)) - { - memcpy (r, state.data, state.size); - r += state.size; - } +#endif return result; } -/* Return a message which says that a PCH file was created with a different - setting of OPTION. */ - -static const char * -pch_option_mismatch (const char *option) -{ - char *r; - - asprintf (&r, _("created and used with differing settings of '%s'"), option); - if (r == NULL) - return _("out of memory"); - return r; -} - /* Default version of pch_valid_p. */ const char * default_pch_valid_p (const void *data_p, size_t len) { - struct cl_option_state state; const char *data = (const char *)data_p; + const char *flag_that_differs = NULL; size_t i; /* -fpic and -fpie also usually make a PCH invalid. */ @@ -1396,73 +4130,82 @@ default_pch_valid_p (const void *data_p, size_t len) data += 2; /* Check target_flags. */ - if (targetm.check_pch_target_flags) + if (memcmp (data, &target_flags, sizeof (target_flags)) != 0) { - int tf; - const char *r; - - memcpy (&tf, data, sizeof (target_flags)); - data += sizeof (target_flags); - len -= sizeof (target_flags); - r = targetm.check_pch_target_flags (tf); - if (r != NULL) - return r; + for (i = 0; i < ARRAY_SIZE (target_switches); i++) + { + int bits; + int tf; + + memcpy (&tf, data, sizeof (target_flags)); + + bits = target_switches[i].value; + if (bits < 0) + bits = -bits; + if ((target_flags & bits) != (tf & bits)) + { + flag_that_differs = target_switches[i].name; + goto make_message; + } + } + abort (); } + data += sizeof (target_flags); + len -= sizeof (target_flags); - for (i = 0; i < cl_options_count; i++) - if (option_affects_pch_p (i, &state)) - { - if (memcmp (data, state.data, state.size) != 0) - return pch_option_mismatch (cl_options[i].opt_text); - data += state.size; - len -= state.size; - } + /* Check string options. */ +#ifdef TARGET_OPTIONS + for (i = 0; i < ARRAY_SIZE (target_options); i++) + { + const char *str = *target_options[i].variable; + size_t l; + if (! str) + str = ""; + l = strlen (str) + 1; + if (len < l || memcmp (data, str, l) != 0) + { + flag_that_differs = target_options[i].prefix; + goto make_message; + } + data += l; + len -= l; + } +#endif return NULL; + + make_message: + { + char *r; + asprintf (&r, _("created and used with differing settings of `-m%s'"), + flag_that_differs); + if (r == NULL) + return _("out of memory"); + return r; + } } /* Default tree printer. Handles declarations only. */ static bool -default_tree_printer (pretty_printer * pp, text_info *text, const char *spec, - int precision, bool wide, bool set_locus, bool hash) +default_tree_printer (pretty_printer * pp, text_info *text) { - tree t; - - /* FUTURE: %+x should set the locus. */ - if (precision != 0 || wide || hash) - return false; - - switch (*spec) + switch (*text->format_spec) { case 'D': - t = va_arg (*text->args_ptr, tree); - if (DECL_DEBUG_EXPR_IS_FROM (t) && DECL_DEBUG_EXPR (t)) - t = DECL_DEBUG_EXPR (t); - break; - case 'F': case 'T': - t = va_arg (*text->args_ptr, tree); - break; + { + tree t = va_arg (*text->args_ptr, tree); + const char *n = DECL_NAME (t) + ? (*lang_hooks.decl_printable_name) (t, 2) + : "<anonymous>"; + pp_string (pp, n); + } + return true; default: return false; } - - if (set_locus && text->locus) - *text->locus = DECL_SOURCE_LOCATION (t); - - if (DECL_P (t)) - { - const char *n = DECL_NAME (t) - ? lang_hooks.decl_printable_name (t, 2) - : "<anonymous>"; - pp_string (pp, n); - } - else - dump_generic_node (pp, t, 0, 0, 0); - - return true; } /* Initialization of the front end environment, before command line @@ -1482,9 +4225,6 @@ general_init (const char *argv0) hex_init (); - /* Unlock the stdio streams. */ - unlock_std_streams (); - gcc_init_libintl (); /* Initialize the diagnostics reporting machinery, so option parsing @@ -1521,7 +4261,6 @@ general_init (const char *argv0) table. */ init_ggc (); init_stringpool (); - linemap_init (&line_table); init_ttree (); /* Initialize register usage now so switches may override. */ @@ -1532,21 +4271,6 @@ general_init (const char *argv0) /* This must be done after add_params but before argument processing. */ init_ggc_heuristics(); - init_optimization_passes (); -} - -/* Return true if the current target supports -fsection-anchors. */ - -static bool -target_supports_section_anchors_p (void) -{ - if (targetm.min_anchor_offset == 0 && targetm.max_anchor_offset == 0) - return false; - - if (targetm.asm_out.output_anchor == NULL) - return false; - - return true; } /* Process the options that have been parsed. */ @@ -1561,26 +4285,14 @@ process_options (void) initialization based on the command line options. This hook also sets the original filename if appropriate (e.g. foo.i -> foo.c) so we can correctly initialize debug output. */ - no_backend = lang_hooks.post_options (&main_input_filename); -#ifndef USE_MAPPED_LOCATION + no_backend = (*lang_hooks.post_options) (&main_input_filename); input_filename = main_input_filename; -#endif #ifdef OVERRIDE_OPTIONS /* Some machines may reject certain combinations of options. */ OVERRIDE_OPTIONS; #endif - if (flag_section_anchors && !target_supports_section_anchors_p ()) - { - warning (OPT_fsection_anchors, - "this target does not support %qs", "-fsection-anchors"); - flag_section_anchors = 0; - } - - if (flag_short_enums == 2) - flag_short_enums = targetm.default_short_enums (); - /* Set aux_base_name if not already set. */ if (aux_base_name) ; @@ -1616,15 +4328,26 @@ process_options (void) if (flag_unroll_all_loops) flag_unroll_loops = 1; - /* The loop unrolling code assumes that cse will be run after loop. - web and rename-registers also help when run after loop unrolling. */ + if (flag_unroll_loops) + { + flag_old_unroll_loops = 0; + flag_old_unroll_all_loops = 0; + } + + if (flag_old_unroll_all_loops) + flag_old_unroll_loops = 1; - if (flag_rerun_cse_after_loop == AUTODETECT_VALUE) - flag_rerun_cse_after_loop = flag_unroll_loops || flag_peel_loops; - if (flag_web == AUTODETECT_VALUE) - flag_web = flag_unroll_loops || flag_peel_loops; - if (flag_rename_registers == AUTODETECT_VALUE) - flag_rename_registers = flag_unroll_loops || flag_peel_loops; + /* Old loop unrolling requires that strength_reduction be on also. Silently + turn on strength reduction here if it isn't already on. Also, the loop + unrolling code assumes that cse will be run after loop, so that must + be turned on also. */ + if (flag_old_unroll_loops) + { + flag_strength_reduce = 1; + flag_rerun_cse_after_loop = 1; + } + if (flag_unroll_loops || flag_peel_loops) + flag_rerun_cse_after_loop = 1; if (flag_non_call_exceptions) flag_asynchronous_unwind_tables = 1; @@ -1636,20 +4359,17 @@ process_options (void) if (flag_unit_at_a_time && ! lang_hooks.callgraph.expand_function) flag_unit_at_a_time = 0; - if (!flag_unit_at_a_time) - flag_section_anchors = 0; - if (flag_value_profile_transformations) flag_profile_values = 1; /* Warn about options that are not supported on this machine. */ #ifndef INSN_SCHEDULING if (flag_schedule_insns || flag_schedule_insns_after_reload) - warning (0, "instruction scheduling not supported on this target machine"); + warning ("instruction scheduling not supported on this target machine"); #endif #ifndef DELAY_SLOTS if (flag_delayed_branch) - warning (0, "this target machine does not have delayed branches"); + warning ("this target machine does not have delayed branches"); #endif user_label_prefix = USER_LABEL_PREFIX; @@ -1663,7 +4383,7 @@ process_options (void) user_label_prefix = flag_leading_underscore ? "_" : ""; } else - warning (0, "-f%sleading-underscore not supported on this target machine", + warning ("-f%sleading-underscore not supported on this target machine", flag_leading_underscore ? "" : "no-"); } @@ -1689,30 +4409,6 @@ process_options (void) /* Now we know write_symbols, set up the debug hooks based on it. By default we do nothing for debug output. */ - if (PREFERRED_DEBUGGING_TYPE == NO_DEBUG) - default_debug_hooks = &do_nothing_debug_hooks; -#if defined(DBX_DEBUGGING_INFO) - else if (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG) - default_debug_hooks = &dbx_debug_hooks; -#endif -#if defined(XCOFF_DEBUGGING_INFO) - else if (PREFERRED_DEBUGGING_TYPE == XCOFF_DEBUG) - default_debug_hooks = &xcoff_debug_hooks; -#endif -#ifdef SDB_DEBUGGING_INFO - else if (PREFERRED_DEBUGGING_TYPE == SDB_DEBUG) - default_debug_hooks = &sdb_debug_hooks; -#endif -#ifdef DWARF2_DEBUGGING_INFO - else if (PREFERRED_DEBUGGING_TYPE == DWARF2_DEBUG) - default_debug_hooks = &dwarf2_debug_hooks; -#endif -#ifdef VMS_DEBUGGING_INFO - else if (PREFERRED_DEBUGGING_TYPE == VMS_DEBUG - || PREFERRED_DEBUGGING_TYPE == VMS_AND_DWARF2_DEBUG) - default_debug_hooks = &vmsdbg_debug_hooks; -#endif - if (write_symbols == NO_DEBUG) ; #if defined(DBX_DEBUGGING_INFO) @@ -1739,31 +4435,6 @@ process_options (void) error ("target system does not support the \"%s\" debug format", debug_type_names[write_symbols]); - /* Now we know which debug output will be used so we can set - flag_var_tracking, flag_rename_registers if the user has - not specified them. */ - if (debug_info_level < DINFO_LEVEL_NORMAL - || debug_hooks->var_location == do_nothing_debug_hooks.var_location) - { - if (flag_var_tracking == 1) - { - if (debug_info_level < DINFO_LEVEL_NORMAL) - warning (0, "variable tracking requested, but useless unless " - "producing debug info"); - else - warning (0, "variable tracking requested, but not supported " - "by this debug format"); - } - flag_var_tracking = 0; - } - - if (flag_rename_registers == AUTODETECT_VALUE) - flag_rename_registers = default_debug_hooks->var_location - != do_nothing_debug_hooks.var_location; - - if (flag_var_tracking == AUTODETECT_VALUE) - flag_var_tracking = optimize >= 1; - /* If auxiliary info generation is desired, open the output file. This goes in the same directory as the source file--unlike all the other output files. */ @@ -1771,39 +4442,39 @@ process_options (void) { aux_info_file = fopen (aux_info_file_name, "w"); if (aux_info_file == 0) - fatal_error ("can%'t open %s: %m", aux_info_file_name); + fatal_error ("can't open %s: %m", aux_info_file_name); } if (! targetm.have_named_sections) { if (flag_function_sections) { - warning (0, "-ffunction-sections not supported for this target"); + warning ("-ffunction-sections not supported for this target"); flag_function_sections = 0; } if (flag_data_sections) { - warning (0, "-fdata-sections not supported for this target"); + warning ("-fdata-sections not supported for this target"); flag_data_sections = 0; } } if (flag_function_sections && profile_flag) { - warning (0, "-ffunction-sections disabled; it makes profiling impossible"); + warning ("-ffunction-sections disabled; it makes profiling impossible"); flag_function_sections = 0; } #ifndef HAVE_prefetch if (flag_prefetch_loop_arrays) { - warning (0, "-fprefetch-loop-arrays not supported for this target"); + warning ("-fprefetch-loop-arrays not supported for this target"); flag_prefetch_loop_arrays = 0; } #else if (flag_prefetch_loop_arrays && !HAVE_prefetch) { - warning (0, "-fprefetch-loop-arrays not supported for this target (try -march switches)"); + warning ("-fprefetch-loop-arrays not supported for this target (try -march switches)"); flag_prefetch_loop_arrays = 0; } #endif @@ -1812,46 +4483,18 @@ process_options (void) make much sense anyway, so don't allow it. */ if (flag_prefetch_loop_arrays && optimize_size) { - warning (0, "-fprefetch-loop-arrays is not supported with -Os"); + warning ("-fprefetch-loop-arrays is not supported with -Os"); flag_prefetch_loop_arrays = 0; } #ifndef OBJECT_FORMAT_ELF -#ifndef OBJECT_FORMAT_MACHO if (flag_function_sections && write_symbols != NO_DEBUG) - warning (0, "-ffunction-sections may affect debugging on some targets"); -#endif + warning ("-ffunction-sections may affect debugging on some targets"); #endif - /* The presence of IEEE signaling NaNs, implies all math can trap. */ - if (flag_signaling_nans) - flag_trapping_math = 1; - - /* With -fcx-limited-range, we do cheap and quick complex arithmetic. */ - if (flag_cx_limited_range) - flag_complex_method = 0; - - /* Targets must be able to place spill slots at lower addresses. If the - target already uses a soft frame pointer, the transition is trivial. */ - if (!FRAME_GROWS_DOWNWARD && flag_stack_protect) - { - warning (0, "-fstack-protector not supported for this target"); - flag_stack_protect = 0; - } - if (!flag_stack_protect) - warn_stack_protect = 0; - - /* ??? Unwind info is not correct around the CFG unless either a frame - pointer is present or A_O_A is set. Fixing this requires rewriting - unwind info generation to be aware of the CFG and propagating states - around edges. */ - if (flag_unwind_tables && !ACCUMULATE_OUTGOING_ARGS - && flag_omit_frame_pointer) - { - warning (0, "unwind tables currently requires a frame pointer " - "for correctness"); - flag_omit_frame_pointer = 0; - } + /* The presence of IEEE signaling NaNs, implies all math can trap. */ + if (flag_signaling_nans) + flag_trapping_math = 1; } /* Initialize the compiler back end. */ @@ -1864,13 +4507,15 @@ backend_init (void) /* Enable line number info for traceback. */ || debug_info_level > DINFO_LEVEL_NONE #endif - || flag_test_coverage); + || flag_test_coverage + || warn_notreached); - init_rtlanal (); init_regs (); init_fake_stack_mems (); init_alias_once (); + init_loop (); init_reload (); + init_function_once (); init_varasm_once (); /* The following initialization functions need to generate rtl, so @@ -1886,20 +4531,12 @@ backend_init (void) static int lang_dependent_init (const char *name) { - location_t save_loc = input_location; if (dump_base_name == 0) - dump_base_name = name && name[0] ? name : "gccdump"; + dump_base_name = name ? name : "gccdump"; /* Other front-end initialization. */ -#ifdef USE_MAPPED_LOCATION - input_location = BUILTINS_LOCATION; -#else - input_filename = "<built-in>"; - input_line = 0; -#endif - if (lang_hooks.init () == 0) + if ((*lang_hooks.init) () == 0) return 0; - input_location = save_loc; init_asm_output (name); @@ -1918,7 +4555,7 @@ lang_dependent_init (const char *name) predefined types. */ timevar_push (TV_SYMOUT); -#if defined DWARF2_DEBUGGING_INFO || defined DWARF2_UNWIND_INFO +#ifdef DWARF2_UNWIND_INFO if (dwarf2out_do_frame ()) dwarf2out_frame_init (); #endif @@ -1957,7 +4594,23 @@ finalize (void) fatal_error ("error closing %s: %m", asm_file_name); } - finish_optimization_passes (); + /* Do whatever is necessary to finish printing the graphs. */ + if (graph_dump_format != no_graph) + { + int i; + + for (i = 0; i < (int) DFI_MAX; ++i) + if (dump_file[i].initialized && dump_file[i].graph_dump_p) + { + char seq[16]; + char *suffix; + + sprintf (seq, DUMPFILE_FORMAT, i); + suffix = concat (seq, dump_file[i].extension, NULL); + finish_graph_dump_file (dump_base_name, suffix); + free (suffix); + } + } if (mem_report) { @@ -1967,14 +4620,13 @@ finalize (void) dump_rtx_statistics (); dump_varray_statistics (); dump_alloc_pool_statistics (); - dump_ggc_loc_statistics (); } /* Free up memory for the benefit of leak detectors. */ free_reg_info (); /* Language-specific end of compilation actions. */ - lang_hooks.finish (); + (*lang_hooks.finish) (); } /* Initialize the compiler, and compile the input file. */ @@ -2003,7 +4655,23 @@ do_compile (void) /* Language-dependent initialization. Returns true on success. */ if (lang_dependent_init (main_input_filename)) - compile_file (); + { + if (flag_unit_at_a_time) + { + open_dump_file (DFI_cgraph, NULL); + cgraph_dump_file = rtl_dump_file; + rtl_dump_file = NULL; + } + + compile_file (); + + if (flag_unit_at_a_time) + { + rtl_dump_file = cgraph_dump_file; + cgraph_dump_file = NULL; + close_dump_file (DFI_cgraph, NULL, NULL_RTX); + } + } finalize (); } diff --git a/contrib/gcc/version.c b/contrib/gcc/version.c index c839cbd..229cf62 100644 --- a/contrib/gcc/version.c +++ b/contrib/gcc/version.c @@ -1,14 +1,12 @@ +/* $FreeBSD$ */ #include "version.h" -/* This is the trailing component of the string reported as the - version number by all components of the compiler. For an official - FSF release, it is empty. If you distribute a modified version of - GCC, please change this string to indicate that. The suggested - format is a leading space, followed by your organization's name - in parentheses. You may also wish to include a number indicating - the revision of your modified compiler. */ +/* This is the string reported as the version number by all components + of the compiler. If you distribute a modified version of GCC, + please modify this string to indicate that, e.g. by putting your + organization's name in parentheses at the end of the string. */ -#define VERSUFFIX "" +const char version_string[] = "3.4.6 [FreeBSD] 20060825"; /* This is the location of the online document giving instructions for reporting bugs. If you distribute a modified version of GCC, @@ -18,8 +16,3 @@ not bugs in your modifications.) */ const char bug_report_url[] = "<URL:http://gcc.gnu.org/bugs.html>"; - -/* The complete version string, assembled from several pieces. - BASEVER, DATESTAMP, and DEVPHASE are defined by the Makefile. */ - -const char version_string[] = BASEVER DATESTAMP DEVPHASE VERSUFFIX; |